Compare commits

...
511 Commits
Author SHA1 Message Date
ptitSeb 5daced4476 [WINE] Fixed some issues with vc_redist.x64.exe that fails to install properly 2026-11-08 13:00:43 +01:00
ptitSeb 20cff3b264 [WINE] Allows wine 11.21+ to start 2026-11-08 12:59:45 +01:00
ptitSeb 37f5e4b7b0 Expand special names in DT_NEEDED names too (for #4682) 2026-11-07 11:26:50 +01:00
ptitSeb 70cdfdb2c2 Fixed proc/self/maps formating (for #4681) 2026-11-07 10:44:59 +01:00
Alex BeverageandClaude Opus 5.5 50855a1e2b [ARM64_DYNAREC] Fix native flags record in signal arch info (#4678)
* [ARM64_DYNAREC] Fix native flags record in signal arch info

The one-bit fields of arch_flags_t were assigned flags&NF_xx directly; only
NF_EQ is bit 0, so SF, OF, CF and PF were always recorded as clear, and a
signal landing on a conditional jump got those flags from emu->df or x26
instead of NZCV. Also drop a stale emu->df when the record isn't deferred,
so the caller's CHECK_FLAGS doesn't recompute the native bits from it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* [ARM64_DYNAREC] Remove comment in adjust_arch

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-06 20:36:04 +01:00
Alex BeverageandClaude Opus 5.5 0b5002e8df [SIGNAL] Restore FPU state and drop deferred flags when a handler changes the context (#4679)
* [SIGNAL] Restore FPU state and drop deferred flags when a handler changes the context

When a guest signal handler returns a modified context, my_sigactionhandler_oldcode_64
leaves through native_next or siglongjmp, and neither goes back through
my_sigactionhandler_oldcode, where the emu state is saved and restored around the
handler. The interrupted code then resumed with the handler's SSE/AVX/x87 registers and
its deferred-flags record. Restore the FPU state from the frame, as sigreturn would, and
drop the deferred flags, since eflags is loaded from the context.

CoreCLR does this on every GC suspension that moves an object a thread holds in a
register (seen as wrong vectorised string compares and wrongly taken bounds checks).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* [SIGNAL] Remove comment in context change path

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-06 20:35:49 +01:00
ptitSeb 4049ceacf0 Windows builds needs ULL to be 64bits 2026-11-06 12:02:52 +01:00
ptitSeb 5c60cf8f42 [ARM64_DYNAREC] Small optimsation for test emitters 2026-11-05 11:39:06 +01:00
Zhijin Zeng 59b3eb1555 [RV64_DYNAREC] Reuse sew to remove vsetvli for avx_load_reg_vector (#4668) 2026-11-05 12:07:06 +08:00
airidosas252 83935bc134 [BOX64EC] Compile Dynarec emitters, add Box64EC register mapping (#4666)
* [BOX64EC] Add the ARM64EC register mapping to the Dynarec

x18 is the TEB and x6 is guest R9 there, so the scratch registers are x1 to x5.

* [BOX64EC] Keep guest R9 out of the Dynarec scratch registers

x6 is R9 in the ARM64EC mapping, so the emitters use x1 to x5 only, with the same code on every target where it is the same size.

* [BOX64EC] Pass PCMPESTRx REX.W without clobbering guest R9

REX.W goes in bit 8 of the imm8 argument, which a small wrapper unpacks.

* [BOX64EC] Adapt Dynarec helper calls to the ARM64EC register map

C calls use LR for the call address, spill R10 and R11 and reload x18 as the TEB, and checkCRC keeps emu on the stack instead of in x6.

* [BOX64EC] Compile Dynarec sources without linking them

The DLL still runs the interpreter.
2026-11-05 12:04:41 +08:00
Yang Liu 27a2d1f81d [WRAPPER] Wrapped CRYPTO_set_mem_functions for libcrypto.so.3 (#4665) 2026-11-03 18:01:15 +01:00
Yang Liu b71b00322e [RV64_DYNAREC] Added autocrc support (#4664) 2026-11-03 15:08:09 +01:00
Yang Liu b640a570b3 [RV64_DYNAREC] Use fence.tso for RET and strongmem barriers (#4663) 2026-11-03 12:18:50 +01:00
Yang Liu 9c5e8a541a [RV64_DYNAREC] Include up32 and rsp in arch state detection (#4662) 2026-11-03 11:55:35 +01:00
Yang Liu 6bee368bd2 [RV64_DYNAREC] Fence stores at RET by default (#4655) 2026-11-03 09:02:07 +01:00
Yang Liu 3d48b55edb [RV64_DYNAREC] Extend nativeflags to 1+N pattern (#4661) 2026-11-03 09:01:21 +01:00
Yang Liu 03d689bf56 [RV64_DYNAREC] Materialize direct call return address from xRIP (#4660) 2026-11-03 09:00:28 +01:00
Yang Liu b8171c2402 [RV64_DYNAREC] Track zero-extension of LEA and SRLIW results (#4659) 2026-11-03 08:58:32 +01:00
Yang Liu d338d4660e [RV64] Reset RVV extensions when vector is disabled (#4658) 2026-11-03 08:57:33 +01:00
Yang Liu 20807c208c [RV64_DYNAREC] Reuse zero-extended operands in fused 32-bit compares (#4657) 2026-11-03 08:56:35 +01:00
Zhijin Zeng 23597f62fd [RV64_DYNAREC] Keep SEW when flushing YMM upper halves to reduce vsetvli (#4652) 2026-11-02 16:03:40 +08:00
Yang Liu 27fd407318 [DYNAREC] Preserved flags when a block is truncated on a fill fault (#4653) 2026-11-02 08:50:52 +01:00
Yang Liu 22f67f2b20 [DYNAREC] Clear pending df on all DIV/IDIV paths (#4651) 2026-11-01 18:47:28 +01:00
Yang Liu 74d9149095 [DYNAREC] Rollbacked a wrong optimization in PR #4648 (#4650) 2026-11-01 16:12:20 +01:00
Yang Liu 37d91ce5ee [RV64_DYNAREC] Fixed cache transform on a back-edge to the block start 2026-11-01 22:22:00 +08:00
Yang Liu 59955e15bb [RV64_DYNAREC] Restore YMM upper halves after a native call 2026-11-01 22:22:00 +08:00
Yang Liu 5cc72d9d7a [RV64_DYNAREC] Reset vtype tracking after native calls 2026-11-01 22:22:00 +08:00
Yang Liu 9f0814e08f [RV64_DYNAREC] Zero-extend SHLD/SHRD destination in 32-bit mode 2026-11-01 22:22:00 +08:00
Yang Liu 89566077a7 [RV64_DYNAREC] Do locked bit ops on the aligned 32-bit word 2026-11-01 22:22:00 +08:00
Yang Liu 0b046f594c [DYNAREC] Fixed deferred 16-bit SHLD/SHRD flags with count>16 (#4648)
* [DYNAREC] Fixed deferred 16-bit SHLD/SHRD flags with count>16

* optim
2026-11-01 11:27:06 +01:00
Yang Liu 93c68acd37 [LA64_DYNAREC] Restore pending scalar XMM values on signal exit (#4647) 2026-10-31 20:06:44 +01:00
Yang Liu 5177ca4732 [LA64_DYNAREC] Fixed AES source being clobbered by AVX cache sync in SCRATCH (#4646) 2026-10-31 20:03:18 +01:00
ptitSeb e86a766cbe [ARM64] Added a dection of write error on segfault using extra signal information (for #4644) 2026-10-31 14:30:55 +01:00
NickletsandClaude Opus 5.5 f60dea9b4b [ARM64_DYNAREC] Keep the guest base register when adding a segment base in geted() (#4645)
For %fs:/%gs:-disp(%reg) with a displacement under 4 KiB that the load can't take as an
immediate, scratch was left pointing at the guest base register, so grab_segdata() loaded the
segment base into it and the next access through that register landed at twice the base.
Give the segment base a real scratch register again (fixes #4643).

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-31 13:37:40 +01:00
ptitSeb d7124fdd64 [DYNAREC] Reused getDB result is InternalDBGetBlock (linked with #4642) 2026-10-31 11:58:24 +01:00
Yang Liu d74ec762c6 [DYNAREC] Don't run a block that intersects a hot page (#4642)
DBGetBlock only checked the page of the block entry address. A block
built before one of its pages became hot kept being validated and
re-protected, so its own store into that page faulted again on every
entry, and the block restarted without making progress.
Check all guest pages covered by the existing block and fall back to the interpreter while any of them is hot.
2026-10-31 08:06:27 +01:00
Yang Liu a7f9094034 [INTERP] Fixed more unaligned LOCK BT* opcodes (#4641) 2026-10-31 07:56:55 +01:00
Yang Liu 6dfbebd2d4 [ARM64_DYNAREC] Fixed YMM upper half lost with VPCLMULQDQ fallback (#4632)
* [ARM64_DYNAREC] Fixed YMM upper half lost with VPCLMULQDQ fallback

native_pclmul_y() reads the Ex operand's upper 128 bits from emu->ymm[ed], but the handler used sse_forget_reg() for Ex, which only marks xmm_used. The upper half was considered dead, so loop merge points skipped materializing its
pending zero. Use sse_reflect_reg() like for Vx.

* [ARM64_DYNAREC] Fixed sse_forget_reg YMM handling
2026-10-30 20:13:21 +01:00
Yang Liu 6367180c2c [ARM64_DYNAREC] Fixed 16-bit BT/BTS/BTR/BTC displacement scale (#4639) 2026-10-30 20:11:44 +01:00
Yang Liu 81e0246b2a [DYNAREC] Small fixes to in_used tracking (#4638) 2026-10-30 20:10:33 +01:00
Zhijin Zeng 8a7a148bdd [RV64_DYNAREC] Translate round mode for some int to float convert opcodes (#4636)
Add sse_setround for CVTSI2SS/CVTDQ2PS/VCVTDQ2PS/CVTSI2SD opcodes.
2026-10-31 00:45:33 +08:00
Zhijin Zeng 6c88bbda42 [RV64_DYNAREC] Keep live XMMs when reflecting cache (#4624)
When BOX64_DYNAREC_TEST is enabled, `dead=1` will corrupt xmm register value.
2026-10-31 00:44:05 +08:00
Yang Liu 75cff5c584 [INTERP] Fixed unaligned LOCK BTS (#4635) 2026-10-30 09:26:41 +01:00
Yang Liu fb0b267f53 [ARM64_DYNAREC] Don't skip dirty preloaded regs on loopback (#4626)
* [ARM64_DYNAREC] Don't skip dirty preloaded regs on loopback

* [ARM64_DYNAREC] Added host_call and refined SSE preload handling
2026-10-30 09:15:05 +01:00
Yang Liu d318afe1b9 [INTERP] Added 16-bit LOCK BTR/BTC/BTS opcodes (#4634) 2026-10-30 09:12:12 +01:00
Yang Liu 5250c6e7a5 [ARM64_DYNAREC] Fixed BOUND leaking a cleared deferred flags state (#4633)
The BOUND handler emits a conditional CALL_S() and then continues. call_c()
clears df and sets dyn->f to status_none, but only on the taken path. The
fall-through kept a pending df while the codegen thought it was cleared, so
the stale deferred op was re-applied later and corrupted the flags. Save and
restore dyn->f around that call.
2026-10-30 08:15:12 +01:00
Zhijin Zeng 7e06f2bd28 [INTERP] Fix some small errors (#4631)
1. sprintf `0x%x` need at least 11 bytes.

2. Fix RDPID opcode
2026-10-30 08:08:22 +01:00
Yang Liu 25418aa192 [ARM64_DYNAREC] Fixed another xmm value lost in a loop (#4630) 2026-10-30 08:05:12 +01:00
Ari (Hamid) Zare 07e9e5c344 Fix typos in documentation (#4629)
Signed-off-by: Hamid Zare <[email protected]>
2026-10-29 16:37:25 +01:00
Yang Liu 5055f947eb [ARM64_DYNAREC] Fixed wrong x87 NaN sign with memory operands (#4628) 2026-10-29 16:26:10 +01:00
Yang Liu 4df6988c9f [ARM64_DYNAREC] Fixed xmm value lost in a loop (#4627)
```
pcmpestrm xmm0, xmm14, 0x2
```
In this opcode, `sse_get_reg_empty()` marked xmm0 old value as dead even when the same opcode had already read it, so loop merge points skipped storing it. And in the second iteration, the C helper of this opcode will have a stale value from memory.
2026-10-29 14:19:55 +01:00
Mark Zhuang 4e8f73c277 [DEBIAN] Fix changelog formatting (#4625)
Before fix:
dpkg-parsechangelog warned about malformed headings,
unrecognized lines, and missing trailers.

Build error on spacemit k3:
bianbu:~/box64$ dpkg-buildpackage -b -uc -us -j8
dpkg-buildpackage: warning:     debian/changelog(l3): badly formatted heading line
LINE: 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!
dpkg-buildpackage: warning:     debian/changelog(l9): badly formatted heading line
LINE: -- Sebastien Chevalier <[email protected]>  Mon, 2 Aug 2026 10:30:33 -0100
dpkg-buildpackage: warning:     debian/changelog(l11): found start of entry where expected more change data or trailer
LINE: box64 (0.4.2) unstable; urgency=low
dpkg-buildpackage: warning:     debian/changelog(l11): found end of file where expected more change data or trailer
dpkg-buildpackage: info: source package box64
dpkg-buildpackage: info: source version 0.4.4
dpkg-buildpackage: info: source distribution unstable
dpkg-buildpackage: info: source changed by
dpkg-buildpackage: error: cannot parse maintainer email address "" from changelog entry

After fix:
Check: dpkg-parsechangelog --all -l debian/changelog -S Version
Result: 0.4.4, no warnings
2026-10-29 09:09:48 +01:00
Yang Liu 30d5c77188 [RV64_DYNAREC] Keep live YMMs cached across merge points, skip dead write-backs (#4610) 2026-10-28 12:16:15 +01:00
Yang Liu ea513ac125 [RV64_DYNAREC] Cleared pending zero on materialized upper halves (#4623) 2026-10-28 11:37:59 +01:00
Zhijin Zeng 3795fe40fb [RV64_DYNAREC] Fix POPCNT/TZCNT/LZCNT with 66h and rex.w prefix (#4622)
For POPCNT/TZCNT/LZCNT, if both the 66H operand-size prefix and REX.W=1 are
present, the effective operand width is 64 bits.

The `dynarec64_F30F` routine handles translation of 64‑bit POPCNT.
2026-10-28 11:37:24 +01:00
Yang Liu 2da641175c [RV64_DYNAREC] Fixed vtype restore skipped by epilog branches (#4621) 2026-10-28 10:40:33 +01:00
Yang Liu ec2f98e95a [RV64_DYNAREC] Fixed up32 handling in some opcodes (#4620) 2026-10-28 10:39:14 +01:00
Yang Liu 4c6be6cb23 [RV64_DYNAREC] Kept pending YMM zero mask on local purges (#4619) 2026-10-28 10:28:16 +01:00
Yang Liu 78217d33fe [RV64_DYNAREC] Reset vtype tracking at block start and reset (#4618) 2026-10-28 10:13:02 +01:00
Yang Liu c4eb274b9a [RV64_DYNAREC] Fixed extcache initialization for preloaded registers (#4617) 2026-10-28 10:12:03 +01:00
Yang Liu 61bbb76bdc [RV64_DYNAREC] Fixed displacement range for some opcodes (#4616) 2026-10-28 10:10:29 +01:00
Yang Liu 13f5aea7d2 [RV64_DYNAREC] Fixed vtype tracking across cache transforms (#4615) 2026-10-28 10:06:48 +01:00
Yang Liu 9cb238fd92 [RV64_DYNAREC] Fixed missing read tracking in AVX register loads (#4614) 2026-10-28 10:05:46 +01:00
Yang Liu 11a20e37c8 [RV64_DYNAREC] Emit scalar AVX FMA with vl=1 (#4613) 2026-10-27 08:26:44 +01:00
Yang Liu 63ed07ac83 [RV64_DYNAREC] Store VMOVSS directly from the vector register (#4612) 2026-10-27 08:10:18 +01:00
Yang Liu 4b7d2eaabe [RV64_DYNAREC] Remove redundant vsetvli from scalar AVX prolog (#4611) 2026-10-27 08:09:29 +01:00
Yang Liu 74ee4280db [DYNAREC] Added callret=3 and move in_used tracking to it (#4609)
Also removed the leafcall optimization from LoongArch.
2026-10-26 16:12:23 +01:00
ptitSeb 11effee660 Arm64 lrcpc (#4608)
* [ARM64_DYNAREC] Use LRCPC2, LRCPC3 (if available) and USCAT for strongmem and volatile metadata

* [ARM64_DYNAREC][LRCPC] Do not use lrcpc if unscaled is not possible on the opcode

* [ARM64_DYNAREC] FFixed an issue with JMP FAR /CALL FAR
2026-10-26 16:00:27 +01:00
Zhijin Zeng 21c14f1c04 [RV64_DYNAREC] Keep origin vtype for VPMOVSX and VPMOVZX opcodes (#4607)
`GETEY_vector_w` already configures SEW and VL for the narrow source.
Use `VEC_SRC_KEEP` instead of `VEC_SRC_SAFE` for VPMOVSX* and VPMOVZX*
to remove reduant vsetvli when the source aliases the destination.
2026-10-26 22:04:23 +08:00
Yang Liu 61add52ed5 [RV64_DYNAREC] Use generic vector stores for XMM spills (#4605) 2026-10-26 08:56:56 +01:00
Yang Liu e9f705df0c [RV64_DYNAREC] Avoid duplicate pending-zero upper stores (#4604) 2026-10-26 08:56:18 +01:00
Yang Liu 319a1a8ad6 [RV64_DYNAREC] Avoid duplicate YMM upper zeroing on SSE cache purge (#4603) 2026-10-26 08:55:04 +01:00
Yang Liu be6e39cdeb [RV64_DYNAREC] Added more AVX opcodes (#4602) 2026-10-26 08:54:21 +01:00
Yang Liu 49341072c8 [RV64_DYNAREC] Optimized a few AVX opcodes (#4601) 2026-10-26 08:52:56 +01:00
Zhijin Zeng a62e03fc7f [RV64_DYNAREC] Fix width error for VMOVSS (#4600)
1. The width of VMOVSS should be 16, which require clearing upper ymm 128 bits.
If set it to 32, the upper 128 bits will not be cleared.

2. Remove unused q1 scratch allocation.
2026-10-26 08:51:35 +01:00
Yang Liu 3c563ba603 [RV64_DYNAREC] Added fast path to extcacheUnwind (#4599) 2026-10-26 08:50:37 +01:00
Yang Liu e8a2f7f9c9 [RV64_DYNAREC] Skipped cache type sync when no vector reg is used (#4598) 2026-10-26 08:49:25 +01:00
Yang Liu 1a49e47075 [RV64_DYNAREC] Fixed stale YMM upper in scalar AVX upper access (#4594) 2026-10-26 08:17:09 +01:00
Yang Liu 1d2083fe59 [RV64][CMAKE] Disabled auto-vectorization (#4596) 2026-10-26 08:06:40 +01:00
Yang Liu d04c270fa9 [RV64_DYNAREC] Fixed dynarec dump buffer overflow (#4595) 2026-10-26 08:05:14 +01:00
Yang Liu 7fffe8dfb5 [RV64_DYNAREC] Fixed CMPXCHG up32 handling (#4593) 2026-10-26 08:04:30 +01:00
Yang Liu a46ad9dfe9 [RV64_DYNAREC] Reworked move immediate (#4591)
* [RV64_DYNAREC] Reworked move immediate

* Use -O2 for test37
2026-10-25 20:57:34 +01:00
Zhijin Zeng 420eda69ff [RV64_DYNAREC] Fix VPERM2I128 vector mask multiple (#4589)
VPERM2I128 only operates on 256-bit vectors, so the vector mask multiple
parameter should be 2.
2026-10-23 21:56:40 +08:00
Zhijin Zeng 5735c8b7c8 [RV64_DYNAREC] Optimize some opcodes by removing redundant some vsetvli (#4588)
When VLMUL, TU, and MU remain unchanged:

For `vmv.s.x`, if SEW stays unchanged, the vector configuration does not need
to change.

For `vmv.v.v`, if the width stays unchanged, the vector configuration does not
need to change.
2026-10-23 21:56:21 +08:00
Zhijin Zeng 827f0ee54e [RV64_DYNAREC] Optimitize VSHUFPS and VPERMILPS 128-bit case 2026-10-23 16:29:30 +08:00
Zhijin Zeng 0b0a31c53c [RV64_DYNAREC] Avoid redundant vsetvli when loading vector masks (#4583)
1. Trim mask immediates to the active vector element count to avoid setting unused
bits.

2. Reuse the vector configuration when its element width can hold all active mask
bits.
2026-10-23 08:15:23 +02:00
Yang Liu 39aae76ddf [RV64_DYNAREC] Optimized some AVX opcodes (#4586) 2026-10-22 14:05:52 +02:00
Zhijin Zeng f267770d75 [RV64_DYNAREC] Optimize contiguous-1-bit cases
MOV64x(x2, 0x7fffffffffffffff);

Before:
```
ADDIW  x2, zero, 1
SLLI   x2, x2, 63
ADDI   x2, x2, -1
```

After:
```
ADDI   x2, zero, -1
SRLI   x2, x2, 1
```
2026-10-22 19:52:13 +08:00
Zhijin Zeng 082ecb92b1 [RV64_DYNAREC] Use bseti for single-bit 64-bit constants
Mov64x(0x800000000000)

Before:
```
ADDIW  reg, zero, 1
SLLI   reg, reg, 47

```

After
```
BSETI  reg, zero, 47
```
2026-10-22 19:52:13 +08:00
ptitSeb fbba162d7c [RCFILE] Optimise steam profile 2026-10-22 10:55:32 +02:00
ptitSeb 8851be9278 [WOWBOX64] Fixed GetEnvironnementVariableA (for #4585) 2026-10-22 10:33:55 +02:00
Zhijin Zeng a111fcafee [RV64_DYNAREC] Fix vector register aliasing 2026-10-22 11:37:38 +08:00
Yang Liu d96343fbb1 [RV64_DYNAREC] Added and optimized some SSE/AVX opcodes (#4581)
* [RV64_DYNAREC] Fixed YMM upper-half pending-zero materialization on scalar path

* [RV64_DYNAREC] Fixed deferred flags left behind on signal exit

* [RV64_DYNAREC] Added and optimized some SSE/AVX opcodes
2026-10-21 10:29:55 +02:00
Yang Liu ae3412c1bf [RV64_DYNAREC] Deferred upper-zero and matched AVX load SEW 2026-10-20 14:20:32 +08:00
Yang Liu db0615cbb0 [RV64_DYNAREC] Used LMUL1 scratch for byte shuffles 2026-10-20 14:20:32 +08:00
Yang Liu 3835fe369e [RV64_DYNAREC] Used vl=1 RVV for scalar SSE/AVX opcodes 2026-10-20 14:20:32 +08:00
Yang Liu d07e3def9c [RV64_DYNAREC] Fixed AVX source/destination aliasing 2026-10-20 14:20:32 +08:00
Yang Liu d0c7da583d [RV64_DYNAREC] Added combined VY/EY/GY vector load macros 2026-10-20 14:20:32 +08:00
Yang Liu 259ba9f554 [RV64_DYNAREC] Used encoded registers for AVX vector operands 2026-10-20 14:20:32 +08:00
Yang Liu 2c3ac5ff08 [RV64_DYNAREC] Forced vsetvli in SSE cache purge 2026-10-20 14:20:32 +08:00
Yang Liu d11def2d5b [RV64_DYNAREC] Kept vtype across linear instructions 2026-10-20 14:20:32 +08:00
Yang Liu d166be5dcc [RV64_DYNAREC] Restricted AES vector path to 128-bit operands 2026-10-20 14:20:32 +08:00
Yang Liu 30449e9255 [RV64_DYNAREC] Fixed YMM upper 128-bit writeback 2026-10-20 14:20:32 +08:00
Yang Liu b9bf3c344d [RV64_DYNAREC] Raised MXCSR invalid flag on overflow 2026-10-20 14:20:32 +08:00
Yang Liu 3ee377b444 [RV64_DYNAREC] Added XMM/YMM preload support 2026-10-20 14:20:32 +08:00
ptitSeb 75ff158c4c [ARM64_DYNAREC] Enlarged a buffer 2026-10-19 15:09:44 +02:00
Yang Liu 66dafa5330 [RV64_DYNAREC] Added and refined more opcodes (#4578) 2026-10-18 10:22:01 +02:00
Zhijin Zeng 27860e6aee [RV64_DYNAREC] Fix VCVTPD2PS result clearing (#4572)
Use SEW=32, LMUL=1, VL=4 to clear the low 128 bits for vcvtpd2ps, which require
clearing bit[127:64] to zero.
2026-10-17 07:24:09 +02:00
Yang Liu 437900559a [RV64_DYNAREC] Purge at merge point with different YMM state (#4576) 2026-10-17 07:21:00 +02:00
Yang Liu 4e91870c51 [DYNAREC] Fixed fpu cache not written back after unused opcodes (again) (#4575)
No code is emitted for unused (unreachable) opcodes, and the fpu cache state is reset there, so the live x87/mmx/sse registers would never be written back and are lost if the block is left on a fault before the next cache purge. Mark the instruction following the unused opcodes as a float barrier, as it starts with no cache, and the cache is then written back before entering it.
2026-10-16 22:00:04 +02:00
Yang Liu b99d44309e [RV64_DYNAREC] Refactored AVX register mapping and register allocation (#4567) 2026-10-16 10:09:26 +02:00
ptitSeb e296745e82 [ARM64_DYNAREC] Fixes some opcode emitter and Special SIGBUS handler 2026-10-15 13:06:52 +02:00
ptitSeb 157dd83ef3 Improved log for Special SIGBUS fixing 2026-10-15 13:04:27 +02:00
Zhijin Zeng d653d0ebef [RV64_DYNAREC] Fix VMOVQ vl (#4569)
The `width` argument of `avx_set_vector_width` is measured in bits rather than
bytes.

This bug results in `vl` being computed as zero.
2026-10-14 11:40:09 +02:00
ptitSeb c51e58b34a Revert "[DYNAREC] Write back the fpu cache before an instruction following un…" (#4570)
This reverts commit 7de6142c98.
2026-10-14 11:26:20 +02:00
Yang Liu 1f7fd2afb0 [INTERP] Fixed more over reads in cosim (#4568) 2026-10-14 09:22:34 +02:00
ptitSeb 4437c9b8b1 [ARM64_DYNAREC] Use LRCPC2 for the UnityHack if LRCPC2 and USCAT cpu extension are available 2026-10-13 19:01:55 +02:00
Zhijin Zeng 986c69cc3e [RV64_DYNAREC] Fix MMX cache corruption in VPERMILPS (#4566)
Allocate the gather scratch register once and reuse it across loop
iterations.

Calling `fpu_get_scratch` for every element advanced the scratch allocator into
v26 and higher, which overlap the registers used by the MMX cache. This could
corrupt live MMX values.

VRGATHER overwrites the scratch register on every iteration, so a single
register can be safely reused.
2026-10-13 19:59:00 +08:00
Zhijin Zeng 868e020d59 [RV64_DYNAREC] Fix incorrect bit position of IE bit in MXCSR (#4565)
MXCSR IE bit is at bit 0, not bit 1.
2026-10-13 19:58:39 +08:00
ptitSeb 45f85efc52 [ARM64] Added LRCPC, LRCPC2 and LRCPC3 detection 2026-10-13 12:33:54 +02:00
ptitSeb ef7005d9ea [DYNAREC] Small refactor on STRONGMEM handling 2026-10-13 11:43:21 +02:00
Yang Liu a95f10cb66 [RV64_DYNAREC] Fixed vector PINSRD opcode and added vector PINSRB opcode (#4564)
* [RV64_DYNAREC] Fixed vector PINSRD opcode and added vector PINSRB opcode

* fix
2026-10-13 08:02:50 +02:00
Yang Liu 93cda37aa6 [INTERP] Fixed some over reads in cosim (#4563) 2026-10-13 08:00:15 +02:00
Zhijin Zeng 0684e43871 [RV64_DYNAREC] Fix PUSHAD and signal state recovery if rsp_merge is enabled (#4562)
1. Save the sp value in PUSHAD by using the pending rsp_entry offset instead
of the stale xRSP value if rsp_merge is enabled.

2. During signal recovery, use the `arch` entry for `ninst` when restoring rsp/up32,
and the `prev_arch` entry for `ninst-1` when restoring FPU.
2026-10-12 18:47:29 +08:00
Yang Liu 7de6142c98 [DYNAREC] Write back the fpu cache before an instruction following unused opcodes (#4561)
No code is emitted for the unused opcodes, so the native registers keep their live values across them. The fpu cache state used to be dropped there, so those live values could not be written back when a block was left on a fault (like a write to a protected code page): the cached x87/mmx/sse registers were lost.

Write the dirty registers back to emu right before the next emitted instruction runs, keeping the cache valid (next=1). The write back is emitted at that instruction entry, so a jump to it runs it too.
2026-10-12 12:15:14 +02:00
Yang Liu ee03a07a17 [RV64_DYNAREC] Fixed some recently introduced issues (#4560)
* [RV64_DYNAREC] Fixed HSUBPS !fastnan handling

* [RV64_DYNAREC] Fixed a missing up32 marker

* [RV64_DYNAREC] Fixed a few scalar AVX GETEX offsets

* [RV64_DYNAREC] Fixed MARKF confliction
2026-10-12 08:46:03 +02:00
Yang Liu c6a8c4472f [RV64_DYNAREC] Fixed a few lock opcodes (#4558) 2026-10-10 18:08:03 +02:00
Zhijin Zeng 397f1f1594 [RV64_DYNAREC] Optimize VMAXPS family opcodes (#4557)
Use vmerge.vvm to reduce instruction counts for vmaxps family opcodes.
2026-10-10 16:58:23 +02:00
Yang Liu 343ff5f1bc [RV64_DYNAREC] Added a few more opcodes (#4556)
* [RV64_DYNAREC] Added a few more opcodes

* fix
2026-10-10 16:55:48 +02:00
Zhijin Zeng c5ddad2a1f [RV64_DYNAREC] Fix ADDI(x1, x1, 0xffff) and ANDI(x1, x1, 0xffff) (#4555)
```
ADDI(x1, x1, 0xffff) -> addi x1, x1, -1
ANDI(x1, x1, 0xffff) -> andi x1, x1, -1
```

1. Zero-extend ADC16 results before testing for zero in d_adc16 and d_adc16b.
`ANDI(x4, x1, 0xffff)` may retain the upper bits.

2. Replace ANDI 0xffff masks with ZEXTH for AAM/AAD operands.

3. Use MOV32w to load the VPHMINPOSUW initial minimum explicitly as 0xffff.
2026-10-10 10:23:55 +02:00
Yang Liu 630c40324c [RV64_DYNAREC] Replaced fpu_purgecache with BARRIER_FLOAT (#4552) 2026-10-10 10:13:55 +02:00
Yang Liu f9bc4a4170 [RV64_DYNAREC] Ported up32 and rsp merge optimization (#4554) 2026-10-10 10:12:53 +02:00
Yang Liu 84972663c5 [RV64_DYNAREC] Fixed x87 FST/FSTP float NaN handling (#4553) 2026-10-10 09:51:55 +02:00
Zhijin Zeng 72cbb140c8 [RV64_DYNAREC] Use ADDSL to replace SLLI+ADD pattern (#4551)
* [RV64_DYNAREC] Use ADDSL to replace shxadd pattern

* [RV64_DYNAREC] Use ADDSL to replace SLLI+ADD pattern
2026-10-10 09:15:53 +02:00
mikolajserediuk a489cfe7d0 [WOWBOX64] Fix exceptions in JIT code above 4GB and pass the fault state to the guest (#4550)
BTCpuResetToConsistentState truncated the host PC to 32 bits before the JIT
lookup, so faults in JIT code above 4GB were not handled and Wine spun in
RtlVirtualUnwind. Also sync the WOW64 context with the guest registers at
the fault, since Wow64PassExceptionToGuest builds the guest context from it.

Fixes #4549
2026-10-09 16:49:38 +02:00
Yang Liu 937d39e71c [ARM64_DYNAREC] Fixed x87 !fastnan handling with both operands are NaN (#4546) 2026-10-09 15:19:50 +02:00
Yang Liu 779d69f2ec [RV64_DYNAREC] Fixed SEW cache after 256-bit AVX instructions (#4548) 2026-10-09 11:11:25 +02:00
Yang Liu 55caa39c60 [TEST] Set emu on the thread (#4547) 2026-10-09 09:26:27 +02:00
Yang Liu 935b6d090f [DYNAREC] Fixed dynablock not getting out when writing in its own page (#4543)
A write faulting on a protected page, with the target not inside the running block, only
unprotected the page and let the block continue. The page then stays writable for the rest
of that block, so a later write of the same block can silently modify code it is going to
execute, and the stale translation gets executed.

So also get out of the block when the target is in the same page as the block, and mark the
write instruction as internal smc so the rebuilt block is cut there. That mark is also used
to not get out a second time, so the write can complete instead of looping.
2026-10-09 09:25:48 +02:00
Yang Liu 6ece2e87f2 [ARM64_DYNAREC] Fixed o64 PCMPESTRI fastpath (#4545) 2026-10-08 17:15:52 +02:00
Zhijin Zeng bffb9ee4d1 [WRAPPER] Add missing parameters for openssl PKCS12_create (#4544)
For openssl 1.0.2,
```
PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
                      int nid_key, int nid_cert, int iter, int mac_iter, int keytype);
```

For openssl 3.0,
```
PKCS12 *PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey,
                      X509 *cert, STACK_OF(X509) *ca,
                      int nid_key, int nid_cert, int iter, int mac_iter, int keytype);
```
2026-10-08 12:36:51 +02:00
ptitSeb f3bec61f27 [ARM64_DYNAREC] Better handling of invalid CS on CALL/RET FAR opcodes (for #4535) 2026-10-08 11:25:12 +02:00
ptitSeb 78ae59d67b [INTERP] Better handling of invalid CS on CALL/RET FAR opcodes 2026-10-08 11:24:28 +02:00
Yang Liu 76f318d453 [DYNAREC] Fixed x87 cache transform not syncing pending stack count (#4538)
* [DYNAREC] Fixed x87 cache transform not syncing pending stack count

* [DYNAREC] Fixed x87 cache transform applying pending stack count twice
2026-10-08 10:51:49 +02:00
Yang Liu b00d767d1a [ARM64_DYNAREC] Fixed ymm_pos encoding in arch restore (#4542) 2026-10-08 10:39:40 +02:00
ptitSeb 2a30952898 [ARM64_DYNAREC] Added a few FLAGM optimisations 2026-10-08 09:29:57 +02:00
Yang Liu 89453f420d [ARM64_DYNAREC] Fixed native flags forwarded from REP CMPS/SCAS with count 0 (#4541)
The flags are not generated when the count is 0 (they are left untouched), so
native flags cannot be forwarded from those instructions.
2026-10-08 09:19:01 +02:00
Zhijin Zeng cf250c5661 [RV64_DYNAREC] Raise illegal inst error for MOVHPS 0F 17 and MOVLPS 0F 13 (#4537)
Also change loogarch movhps 0f 17 opcode.
2026-10-08 09:15:11 +02:00
Yang Liu a43469d7a5 [RV64_DYNAREC] Refined registers restore on interrupted block (#4540) 2026-10-08 09:05:21 +02:00
Yang Liu 430a408f0a [ARM64_DYNAREC] Fixed x87 top restore on interrupted block (#4539) 2026-10-08 09:01:22 +02:00
Yang Liu c269865bb2 [LA64_DYNAREC] Refined vector registers restore (#4536)
* [LA64_DYNAREC] Refined vector registers restore

* [LA64_DYNAREC] Fixed x87 stack count not synced when leaving a block
2026-10-08 08:49:11 +02:00
Yang Liu 2f47bdff3a [INTERP] Fixed FIST/FISTP/FISTTP range check (#4534) 2026-10-07 09:47:58 +02:00
Yang Liu 8f6ab59fc6 [INTERP][DYNAREC] Fixed PCMP opcodes REX.W/VEX.W handling (#4533) 2026-10-06 13:40:09 +02:00
Yang Liu bc41dacc8c [DYNAREC] Fixed FILD/FLD1/FLDZ/FPTAN ignoring BOX64_DYNAREC_X87DOUBLE (#4532) 2026-10-06 10:37:43 +02:00
Yang Liu b1fc0735bb [LA64_DYNAREC] Fixed masked memory access and operand width (#4530) 2026-10-06 08:19:50 +02:00
Yang Liu 0c2de1f7f2 [INTERP][DYNAREC] Fixed x87 indefinite and NaN handling (#4531) 2026-10-06 08:17:32 +02:00
airidosas252 d58d619e84 [BOX64EC] Enable Interpreter execution (#4480)
* [BOX64EC] Add interpreter build dependencies

* [BOX64EC] Add interpreter runtime declarations

* [BOX64EC] Extend context handling for execution

* [BOX64EC] Add the interpreter execution loop

* [BOX64EC] Handle x64 execution entry

* [BOX64EC] Handle transitions to native code

* [BOX64EC] Handle emulated syscalls

* [BOX64EC] Handle guest exceptions and continuation

* [BOX64EC] Add ARM64EC entry and return trampolines

* [BOX64EC] Wire interpreter execution into Wine

* [BOX64EC] Preserve SIMD registers across x64 callbacks

* [BOX64EC] Remove unused transition code

* [BOX64EC] Fix unwinding across the native stack switch

* [BOX64EC] Fix INT3 exception address and saved RIP

* [BOX64EC] Fix INT 2D continuation
2026-10-05 15:14:58 +02:00
The412BannerandThe412Banner abfb8c3b2f [WRAPPER] gstreamer: need GLib's object system, not libgtk-3 (#4528)
* [WRAPPER] gstreamer: need GLib's object system, not libgtk-3

The gstreamer wrapper bridges GObject classes through gtkclass.c, so it
needs libgobject/libglib loaded, but it makes no GTK call. Listing
libgtk-3.so.0 as a needed lib made every GStreamer user fail where GTK is
not installed - an Android rootfs running Wine has GStreamer and no GTK,
so winegstreamer could never decode video there (the WMV decoder reports
CLASS_E_CLASSNOTAVAILABLE, games skip their cutscenes).

Name the GLib libraries the wrapper actually depends on instead.

* [WRAPPER] gstreamer: drop libgio-2.0 from NEEDED_LIBS and remove comment

---------

Co-authored-by: The412Banner <[email protected]>
2026-10-04 09:50:38 +02:00
Yang Liu 9ad27f276d [LA64_DYNAREC] Fixed a regression introduced by commit 78bf553c (#4529)
Fixed 32-bit Linux LIMBO.
2026-10-04 09:01:28 +02:00
Yang Liu e5afb47da8 [WRAPPER] Fixed SMC handling with host pages larger than 4k (#4527)
* [WRAPPER] Fixed SMC handling with host pages larger than 4k

* Try to fix non-dynarec build
2026-10-03 19:39:27 +02:00
Yang Liu 66e4dafa8b [GDBJIT] Fixed generated temp files not being deleted (#4526) 2026-10-03 13:19:05 +02:00
ptitSeb f5ffcd0a04 [ARM64_DYNARED] Fixed potential issue where pending ymm0 is forgotten (linked to #4520) 2026-10-01 14:20:39 +02:00
ptitSeb 77117b80ae Revert "[ARM64_DYNAREC] Fixed pending YMM upper-lane zeroing dropped by cache…" (#4525)
This reverts commit c78eea5fee.
2026-10-01 10:39:11 +02:00
Yang Liu a342e5c9ee [WRAPPER] Fixed CREATE_VALIST_FROM_VAARG macro (#4524)
* [WRAPPER] Fixed CREATE_VALIST_FROM_VAARG macro

This fixes game launching in latest Linux Steam

* review
2026-10-01 09:23:51 +08:00
ptitSeb 2558cfa20b [INTERP] More accurate way to check if execution flag is set or not 2026-09-30 19:59:44 +02:00
ptitSeb 45378965aa [WRAPPER] Try to avoid a potential crash on exit 2026-09-30 18:39:29 +02:00
Yang Liu e6f795ed9c [ARM64_DYNAREC] Fixed BEXTR OF/SF flags (#4523) 2026-09-30 15:48:35 +02:00
Yang Liu 2f0b5b2100 [RV64_DYNAREC] Fixed stale register cache after unreachable code (#4522)
This is only needed by RISC-V backend because of the `olds[]` stuff. It's a nop on other backends.
2026-09-30 14:40:40 +02:00
Yang Liu d3acacac95 [ARM64_DYNAREC] Fixed PCMPESTRI operand length clamping (#4521)
Clamp the EAX/EDX operand lengths with unsigned compare, so length like 0x80000000 normalizes to the element count instead of staying negative.
2026-09-30 14:22:14 +02:00
Zhijin Zeng a56756600a [RV64_DYNAREC] Remove source register dirty flag for MOVHPS (#4516)
Gx is source register operand, and it's value keep unchanged, not need to
set dirty flag.
2026-09-30 19:59:46 +08:00
ptitSeb 1b53452856 [ARM64_DYNAREC] Added 0F 17 /r UD 2026-09-30 13:48:03 +02:00
ptitSeb 2cb3abdedb [INTERP] Added 0F 17 /r UD (ref'd in #4516) 2026-09-30 13:47:24 +02:00
Yang Liu c78eea5fee [ARM64_DYNAREC] Fixed pending YMM upper-lane zeroing dropped by cache reset (#4520) 2026-09-30 13:42:54 +02:00
Yang Liu e0c5937777 [ARM64_DYNAREC] Made some macros safe (#4519)
This fixed the safeflags=2 support for opcodes like `SHRD Ew, Gw, CL`, where the `else` generates wrong code without this fix.
2026-09-30 13:38:40 +02:00
Yang Liu 4e572b7b86 [DYNAREC] Fixed 8-bit XADD opcode (#4518) 2026-09-30 13:37:25 +02:00
Yang Liu baf179bd46 [RV64_DYNAREC] Fixed 16-bit LEA opcode (#4517) 2026-09-30 13:34:55 +02:00
Yang Liu 1b16bc1a3b [RV64_DYNAREC] Fixed VPINSRB opcode (#4515) 2026-09-30 13:22:10 +02:00
Yang Liu 232ec8f9e1 [RV64_DYNAREC] Fixed more opcodes (#4514) 2026-09-30 13:16:32 +02:00
Yang Liu 48ff0ddebc [RV64_DYNAREC] Fixed more opcodes (#4513) 2026-09-30 13:15:00 +02:00
Zhijin Zeng 40ff0e3688 [WRAPPER] Fix some libxml2 signatures (#4512)
```
int xmlValidateDtd (xmlValidCtxt *ctxt, xmlDoc *doc, xmlDtd *dtd);
int xmlParseEnumeratedType (xmlParserCtxt *ctxt, xmlEnumeration **tree);
```
2026-09-30 12:12:45 +02:00
Yang Liu 970ba62254 [LA64_DYNAREC] Fixed ENTER opcode (#4511) 2026-09-30 10:28:35 +02:00
Yang Liu 02fc0325c8 [LA64_DYNAREC] Fixed PDEP/PEXT opcodes (#4510) 2026-09-30 10:11:44 +02:00
Yang Liu 0ee43100e1 [ARM64_DYNAREC] Fixed VCVTPH2PS opcode (#4509) 2026-09-30 10:08:06 +02:00
Yang Liu 8397d31268 [RV64_DYNAREC] Fixed a few more opcodes (#4508) 2026-09-30 10:07:18 +02:00
Yang Liu ce74770e22 [ARM64_DYNAREC] Fixed VPERM2F128 opcode (#4507) 2026-09-30 10:05:47 +02:00
ptitSeb 3787548a9a [WRAPPER] Added a few more wrapped functions to systemd (for gameoverlayui) 2026-09-30 10:04:56 +02:00
Yang Liu c4632305ca [RV64_DYNAREC] Fixed more opcodes (#4506) 2026-09-30 08:50:39 +02:00
Yang Liu b4c92227b1 [RV64_DYNAREC] Fixed typos in scalar AES opcodes (#4505) 2026-09-30 08:49:26 +02:00
Yang Liu a028bd0e91 [TEST] Added memory check (#4504) 2026-09-30 08:48:20 +02:00
Yang Liu 3ce98ac36a [RV64_DYNAREC] Fixed more opcodes (#4502) 2026-09-30 08:16:35 +02:00
Yang Liu 9c72206aae [INTERP] Fixed FMA opcodes (#4503) 2026-09-30 08:04:57 +02:00
Zhijin Zeng 4d303a7c48 [WRAPPER] Fix XCB Render and Sync signatures (#4501)
1. `xcb_render_free_picture_checked`, `xcb_sync_destroy_counter`, and `xcb_sync_set_counter`
return `xcb_void_cookie_t` rather than floating-point or pointer values.

```
 typedef struct {
      unsigned int sequence;
  } xcb_void_cookie_t;
```

2. The Sync wrappers also treated 32-bit counter IDs as pointers and declared extra arguments.

```
xcb_void_cookie_t xcb_sync_destroy_counter(xcb_connection_t *conn, xcb_sync_counter_t counter);
xcb_void_cookie_t xcb_render_free_picture(xcb_connection_t *conn, xcb_render_picture_t picture);
xcb_void_cookie_t xcb_sync_set_counter(xcb_connection_t *conn, xcb_sync_counter_t counter, xcb_sync_int64_t value);
```
2026-09-30 08:01:14 +02:00
Zhijin Zeng 2a06231169 [RV64_DYNAREC] Fix scalar-version VPMASKMOVD/Q (#4500)
If the mask bit is zero, VPMASKMOVD/Q must skip memory access for inactive
lanes, so that memory faults are not raised.
2026-09-30 10:09:21 +08:00
Zhijin Zeng 2ad3ee9151 [RV64_DYNAREC] Fix ENTER opcode (#4499)
RBP is actually left unchanged, yet RBP must be decremented.

```
PUSH EBP;
FRAME_PTR := ESP;
IF LEVEL > 0
  THEN
  DO (LEVEL − 1) times
    EBP := EBP − 4;
    PUSH Pointer(EBP); (* doubleword pointed to by EBP *)
  OD;
  PUSH FRAME_PTR;
FI;
EBP := FRAME_PTR;
ESP := ESP − STORAGE;
```
2026-09-30 10:08:26 +08:00
Zhijin Zeng 557f76cb46 [RV64_DYNAREC] Fix scalar-version VPSLLDQ (#4498)
1. If 8 <= imm <= 15, VPSLLDQ should clear the low half and write the shifted value
to the high half. The high half and low half are incorrectly swapped.

2. The upper-lane result was incorrectly stored using `fixedaddress` instead of the
destination `vyoffset`.
2026-09-30 10:07:41 +08:00
Zhijin Zeng c1d62abf8c [RV64_DYNAREC] Fix source register and sign-bit handling for scalar-version VTESTPS/D (#4497)
1. VTESTPS and VTESTPD encode their second source operand as GX, not VX.

2. The instructions also test only the sign bit of each packed element, rather
than every bit in the source operands.
2026-09-30 10:07:02 +08:00
Yang Liu 50069bcf69 [RV64_DYNAREC] Added more opcodes (#4496) 2026-09-29 09:12:29 +02:00
Yang Liu e1eee0855a [RV64_DYNAREC] Fixed SS/SD size change (#4495) 2026-09-28 18:35:35 +02:00
Yang Liu 0f35bd7e3d [ARM64_DYNAREC] Fixed PCLMULQDQ opcode (#4494) 2026-09-28 17:51:59 +02:00
Yang Liu 7914fed533 [LA64_DYNAREC] Fixed MOVUPD opcode (#4493) 2026-09-28 17:35:25 +02:00
Yang Liu 1a478ee6ae [RV64_DYNAREC] Fixed some opcodes (#4492) 2026-09-28 17:32:17 +02:00
Yang Liu 7b23f2b5a7 [RV64_DYNAREC] Optimized VPERMPD/VPERMQ opcodes (#4491) 2026-09-28 14:10:00 +02:00
Yang Liu ddd8ff7379 [BOX32] Count 32-bit guest threads as active emu workers (#4490) 2026-09-28 13:27:40 +02:00
Yang Liu 6650ba5b68 [BOX32] Publish the guest pthread_t before the new thread starts (#4489) 2026-09-28 11:51:48 +02:00
Zhijin Zeng 486ebebfc2 [RV64_DYNAREC] Fix register aliased errors for scalar-version VPERMQ/VPERMPD (#4486)
1. Support GX==EX for scalar-version VPERMQ/VPERMPD

2. Add UDF if vex.l==0.

3. Scalar-version VPERMQ and VPERMPD share the same code.
2026-09-28 16:58:55 +08:00
Zhijin Zeng 4f253fd85c [RV64_DYNAREC] Fix uc.mcontext value for float-pointint store inst (#4487)
Should use `uc_mcontext.__fpregs.__d.__f[val];` instead of `uc_mcontext.__fpregs.__d.__f[val<<1];`
2026-09-28 16:57:53 +08:00
Yang Liu 4a2f139b1c [TEST] Updated stale tests32/test09 (#4488) 2026-09-28 10:56:27 +02:00
Yang Liu c4e9a19fc9 [DYNACACHE] Added exit_group syscall handling and signal32 SIG_QUIT handling (#4485) 2026-09-28 10:55:38 +02:00
Yang Liu b80b3304c3 [DYNACACHE] Do not serialize when exiting from a fatal signal handler (#4482)
* [DYNACACHE] Do not serialize when exiting from a fatal signal handler

* review
2026-09-28 10:21:37 +02:00
Yang Liu 7895d298c4 [DYNACACHE] Delete invalid cache files on load failure (#4484) 2026-09-28 09:17:53 +02:00
Yang Liu 4238c8eb6f [DYNACACHE] Reset in_used and skip to_delete dynablocks on cache load (#4483) 2026-09-28 09:16:46 +02:00
Yang Liu 4c231eb087 Added support for thread cleanups (#4479)
for #4478
2026-09-28 08:59:23 +02:00
Yang Liu c61543e47b [DYNAREC] Removed the secondary entry points (#4464) 2026-09-27 17:51:14 +02:00
Yang Liu a8e529c6c0 [WRAPPER] Fixed g_object_new varargs clobbered by class_ref (#4477)
g_type_class_ref() can run guest class_init code, which clobbers the varargs
registers; capture the va_list before it.
2026-09-27 17:30:38 +02:00
Yang Liu 537c562c7c [WRAPPER] Added more wrapping for GTK2 (#4476) 2026-09-27 17:22:01 +02:00
airidosas252 906dc9636d [BOX64EC] Add guest context handling (#4472) 2026-09-27 21:40:00 +08:00
ptitSeb 9f285eab00 Added a hint to enable box32 on non-box32 enabled build when trying to run a 32bits binary 2026-09-27 10:33:48 +02:00
Yang Liu d5da4d32ed [RV64_DYNAREC] Fixed some opcodes (#4475) 2026-09-27 10:31:40 +02:00
Yang Liu 967bccf7f3 [RV64_DYNAREC] Added more opcodes (#4474)
* [RV64_DYNAREC] Added more opcodes

* review
2026-09-27 10:26:00 +02:00
ptitSeb ac9b13a54f Fixed D2LD subnormal handling 2026-09-26 09:32:56 +02:00
ptitSeb 685314c56e Fixed LD2D denormal handling 2026-09-26 09:18:30 +02:00
ptitSeb 5d797f351d Try to avoid a potential segfault when quitting 2026-09-26 09:18:03 +02:00
Yang Liu e3ab37bd05 [WRAPPER] Unwrapped GObject classes in g_object_new (#4471)
* [WRAPPER] Unwrapped GObject classes in g_object_new

* oops

* handling guest registed classes
2026-09-25 12:07:33 +02:00
ptitSeb 58c9082b10 Revert "[WRAPPER] Unwrapped GObject classes in g_object_new (#4463)" (#4470)
This reverts commit e4dc7b5e3c.
2026-09-25 08:31:39 +02:00
airidosas252 0b89f9d9b5 [BOX64EC] Introduce thread handling (#4467)
* [BOX64EC] Avoid x86 intrinsic headers with ARM64EC compilation

* [BOX64EC] Skip EmuCall until the interpreter and dynarec are wired up

* [BOX64EC][CMAKE] Build the emulator and thread helpers

* [BOX64EC] Add per-thread emulator state

* [BOX64EC] Prevent double-free during thread cleanup
2026-09-25 09:51:17 +08:00
ptitSeb 494430c6ff Revert "[SIGNAL] Fixed the x86_64 signal frame layout (#4462)" (#4468)
This reverts commit 806d23db92.
2026-09-24 18:41:32 +02:00
Yang Liu db3cc44adc [DYNAREC] Kept in-use dynablocks when flushing at shutdown (#4466) 2026-09-24 17:46:17 +02:00
Yang Liu e4dc7b5e3c [WRAPPER] Unwrapped GObject classes in g_object_new (#4463)
* [WRAPPER] Unwrapped GObject classes in g_object_new

* oops
2026-09-24 12:10:33 +02:00
Yang Liu 806d23db92 [SIGNAL] Fixed the x86_64 signal frame layout (#4462) 2026-09-24 11:34:48 +02:00
airidosas252 851933bde9 [BOX64EC] Miscellaneous Box64EC-specific additions (#4461)
* [BOX64EC] Initialize system information and host CPU features

* [BOX64EC] Add Wine CPU area definitions

* [BOX64EC] Use Box64EC CPU branding
2026-09-24 17:01:57 +08:00
airidosas252 c3b5282050 [BOX64EC] Add support for loading .box64rc file (#4459) 2026-09-23 21:45:33 +08:00
Zhijin Zeng 7df4af9983 [RV64_DYNAREC] Fix VRSQRTPS(-0.0f) with fastnan=0 (#4458)
Use the original zero input as the FDIV.S denominator instead of the +0.0f
scratch value.

If original input is -0.0f, VRSQRTPS should return -inf instead of +inf.
2026-09-23 21:44:37 +08:00
Yang Liu 729c25da67 [DYNAREC] Fixed a regression introduced by 92527ded3 (#4460) 2026-09-23 11:42:53 +02:00
Demetrios Chiuratto AgourakisandDemetrios Chiuratto Agourakis 51b5f8cfc2 x64: Add 16-bit RDRAND and RDSEED (66 0F C7 /6 and /7) (#4457)
Addresses #4368.

- Implement 16-bit operand forms of RDRAND Ew (66 0F C7 /6) and
  RDSEED Ew (66 0F C7 /7) in the x64 interpreter (src/emu/x64run660f.c).
- Implement matching dynarec support in ARM64 JIT (src/dynarec/arm64/dynarec_arm64_660f.c).
- Correctly set CF=1, clear OF/SF/ZF/AF/PF, and write only the lower 16 bits
  to the destination register or memory.

Co-authored-by: Demetrios Chiuratto Agourakis <[email protected]>
2026-09-23 09:39:53 +02:00
Zhijin Zeng 34f858f1bd [WRAPPER] Share special-file handling across open/open64/fopen64 (#4453)
1. Factor the duplicated procfs, sysfs, and synthetic-file handling used by
open/open64/fopen64 into a common helper while retaining each API's native
fallback.

2. Use CreateCpuCacheSize() for cache size entries so they report cache
sizes instead of associativity values.

3. Fix O_WRONLY for open, should use `flags & O_WRONLY` rather than
`mode & O_WRONLY`.
2026-09-23 08:58:44 +02:00
airidosas252 a3124f3001 [BOX64EC] Add CPU feature reporting and env var initialization (#4454)
* [BOX64EC] Introduce CPU feature enumeration

* [BOX64EC] Implement basic env var initialization

* [BOX64EC] Move process initialization into its own box64ec_init.c module

* [BOX64EC][CMAKE] Build with shared Box64 and Wine helpers
2026-09-23 12:40:43 +08:00
Zhijin Zeng 9e6cf49acf [WRAPPER] Fix fts_children signature error (#4452) 2026-09-22 12:30:23 +02:00
ptitSeb 0209199922 [ELFLOADER] Refuse to open a file as a lib if elf is not marked as ET_DYN 2026-09-22 12:13:54 +02:00
Yang Liu 572cdff98b [WRAPPER] Wrapped more symbols for smime3 (#4451) 2026-09-22 10:05:53 +02:00
Zhijin Zeng 66a60835a7 [WRAPPER] Fix aio_read family function signature errors (#4450) 2026-09-22 10:03:56 +02:00
Zhijin Zeng 6290f2b6a4 [DYNAREC] Fix FNSAVE/FRSTOR data direction (#4447)
fnsave should use D2LD when storing x87 double values into the 80-bit memory
area.

frstor should use LD2D when restoring values from the 80-bit memory area.
2026-09-22 08:24:41 +02:00
Yang Liu 477a00df49 [INTERP] Fixed missing alternate lookups for Jcc and short jmp (#4449)
Conditional and short jumps now look up the alternate address table, as calls and jumps already do.
2026-09-22 08:14:55 +02:00
Zhijin Zeng 944a6f8c55 [WRAPPER] Add missing flags arg in open64 (#4446) 2026-09-22 08:11:22 +02:00
Yang Liu 6a8433a019 [DYNAREC] Kept orphan dynablocks in in_used tracking (#4445) 2026-09-22 08:08:38 +02:00
airidosas252 9c5c904adf [CI] Add Box64EC build workflow (#4443) 2026-09-22 10:09:53 +08:00
Yang Liu fbbb0544f7 [WRAPPER] Fixed a few wrapping issues (#4442) 2026-09-21 14:36:39 +02:00
Zhijin Zeng cd3cea460c [RV64_DYNAREC] Fix aliased operands for scalar-version VPACKUSDW (#4434)
* [RV64_DYNAREC] Fix aliased operands for scalar-version VPACKUSDW

Handle in three cases:

1. When `ed == vex.v` and `gd == ed == vex.v`, the computed result of `ed`
matches `vex.v`. Thus overwriting `ed` has no effect, we can get it's high
64-bits data from it's low 64 bits data.

2. When `gd == ed`, retrieve the high 64-bit data by processing `ed` first,
to prevent overwriting the low 64-bit source data of `ed` when processing
`vex.v` beforehand.

3. For `gd == vex.v` and all other cases, keep the original implementation.

* Move PACKUSDW_FILL_ELEMENT to dynarec_rv64_helper.h

* Remove comments

* Revert "Move PACKUSDW_FILL_ELEMENT to dynarec_rv64_helper.h"

This reverts commit 9f4215ea32.

* Remove macro PACKUSDW_FILL_ELEMENT
2026-09-21 18:31:04 +08:00
airidosas252 d5054d6cb8 [BOX64EC][CMAKE] Introduce initial Box64EC skeleton (#4436)
* [CMAKE] Add option to build Box64EC PE DLL module

* [BOX64EC/CMAKE] Add initial CMakeLists.txt file for building Box64EC

* [BOX64EC] Add initial Box64EC skeleton
2026-09-21 18:29:56 +08:00
Yang Liu 18bd20f56d [RV64_DYNAREC] Made more micro optimizations (#4441) 2026-09-21 11:57:07 +02:00
Zhijin Zeng b192486245 [CORE] Fix FILE leak for readBinarySizeFromFile (#4440)
Add missing fclose for readBinarySizeFromFile
2026-09-21 17:32:59 +08:00
Yang Liu 6add5c1406 [STEAM] Updated profile (#4433)
* [STEAM] Updated profile

* Address review and more
2026-09-21 09:04:12 +02:00
Yang Liu de761a83e9 [RV64_DYNAREC] Made many micro optimizations (#4439)
* [RV64_DYNAREC] Made many micro optimizations

* xthead deserves this too

* And more

* moremoremore
2026-09-21 08:13:07 +02:00
Zhijin Zeng a0017eac98 [RV64_DYNAREC] Add MXCSR rounding translation in VCVTPD2PS (#4435)
VCVTPD2PS lacks round mode translation, add it now.
2026-09-21 10:21:13 +08:00
Zhijin Zeng db0873caec [RV64_DYNAREC] Optimize PMULUDQ opcode (#4438)
Change `vslli x2, x3, 32`+`vsrli x2, x2, 32` to `vand x2, x3, 0xffffffffUL`

Vector instructions have higher overhead than scalar ones. Although `mov64x`
for constructing `0xffffffff` keeps the total instruction count unchanged,
we still gain an overall benefit.
2026-09-21 09:45:59 +08:00
Zhijin Zeng f332ae2ba2 [RV64_DYNAREC] Optimize MASKMOVDQU mask extraction (#4437)
Under SEW=8 configuration, bit7 of each byte indicates sign. We can directly
check if elements are less than zero.
2026-09-21 09:43:10 +08:00
yzewei 3f34d1e7e6 [INTERP] Honor MXCSR rounding mode in SSE/AVX operations (#4408)
The interpreter implements a number of SSE and AVX instructions using
host floating-point operations, but did not apply the guest MXCSR.RC
before performing them. As a result, directed rounding modes could
produce results using the host's previous rounding mode.

Add mxcsr_setround() to save the host rounding mode and temporarily
apply the rounding mode selected by the guest MXCSR. Use it around the
affected SSE and AVX arithmetic, horizontal, dot-product, conversion,
and FMA interpreter paths, restoring the original host mode afterward.

Add an interpreter regression test covering all four MXCSR rounding
modes and representative scalar, packed, conversion, AVX, and FMA
instructions. Force the test through the interpreter so that a dynarec
path cannot hide interpreter rounding errors.

Signed-off-by: Zewei Yang <[email protected]>
2026-09-21 09:09:47 +08:00
ptitSeb 002d10833d [DOC] Added 1 more hardware contributor, thanks! 2026-09-20 16:28:54 +02:00
Yang Liu a92a0263eb [BOX32][X11] Fixed refreshDisplay() on an unregistered Display (#4431) 2026-09-20 10:20:09 +02:00
Yang Liu 07c37e1c4d [LIBRARIAN] Fixed dlopen/dlsym/dlclose races (#4429) 2026-09-20 10:16:20 +02:00
Yang Liu 90efb9a7d8 [MEMORY] Fixed blockstree locking (#4427)
* [MEMORY] Fixed blockstree locking

* Fix
2026-09-20 10:15:03 +02:00
airidosas252andairidosas252 454d538757 [WINE] Add LLVM-mingw ARM64EC toolchain support (#4432)
Co-authored-by: airidosas252 <[email protected]>
2026-09-20 11:13:17 +08:00
Yang Liu 38f4831b24 [BOX32][X11] Fixed in-place WM hints conversion (#4430) 2026-09-19 08:20:04 +02:00
Yang Liu e5ff132dc3 [ELFLOADER] Fixed TLS data races with mutex_tls (#4428) 2026-09-19 08:14:48 +02:00
Zhijin Zeng b4bc7c2e46 [RV64_DYNAREC] Fix scalar-version VPERM2I128 (#4425)
Load all selected source lanes before writing the destination, so an aliased
destination cannot overwrite data needed for the other lane.
2026-09-19 11:37:18 +08:00
Zhijin Zeng 6f7a215578 [ELFLOADER] Fast reject addresses outside ELF reservations (#4424)
Use the raw ELF mapping boundaries to skip the PT_LOAD block scan when an
address is outside the reserved image range.
2026-09-18 15:33:53 +02:00
Yang Liu 5fb1da8cd6 [RV64_DYNAREC] Fixed PHMINPOSUW opcode (#4423) 2026-09-18 15:15:48 +02:00
Yang Liu 86c7a8f354 [RV64_DYNAREC] Fixed some LOCK prefix opcodes (#4422) 2026-09-18 14:46:47 +02:00
Yang Liu 9f69ee9310 [RV64_DYNAREC] Fixed VROUNDPS/D opcodes (#4421) 2026-09-18 14:37:01 +02:00
Yang Liu 9dd0bb4b40 [RV64_DYNAREC] Fixed SHA opcodes (#4420) 2026-09-18 12:57:43 +02:00
Zhijin Zeng e74c6438b7 [CORE] Add marco ALIGN_DOWN (#4419)
1. Move ALIGN to debug.h and dd marro ALIGN_DOWN.

2. Change `p & ~(box64_pagesize-1)` to `ALIGN_DOWN(p)`.

3. Change `(p+box64_pagesize-1) & ~(box64_pagesize-1)` to `ALIGN(p)`.
2026-09-18 12:31:15 +02:00
Yang Liu ba0d84bd9e [DYNAREC] Fixed LOCK CMPXCHG16B mutex_16b addressing (#4418) 2026-09-18 10:15:55 +02:00
Zhijin Zeng 560bfed198 [RV64_DYNAREC] Use BEXTI to extract single bits instead of SRLI+ANDI (#4415)
1. Use BEXTI to replace `SRLI(x5, x1, imm); ANDI(x3, x5, 1);` if x5 is only a
temporary variable.

2. In BEXTI, SRLIW and SRLI are equivalent here, since we will clear the upper
63 bits with ANDI afterwards. Using SRLI directly saves one instruction.

3. BEXTI already checks for zbs, so no external check is needed.
2026-09-18 14:22:23 +08:00
Yang Liu 8f5d6e7be1 [RV64_DYNAREC] Added more opcodes (#4417) 2026-09-18 08:20:43 +02:00
Yang Liu 1e51dbdcae [RV64_DYNAREC] Fixed LOCK NEG opcode (#4416) 2026-09-18 08:19:10 +02:00
Yang Liu 3bb457940a [RV64_DYNAREC] Fixed a few non-zbb path introduced recently (#4414) 2026-09-18 08:14:58 +02:00
Yang Liu 422a9f9d19 [RV64_DYNAREC] Adapted VPACKUSDW opcode to the new SATUw macro (#4413) 2026-09-18 08:13:49 +02:00
Yang Liu 496fb4bebf [DYNAREC] Made the zombie Dynablocks buffer bigger (#4412) 2026-09-17 19:28:28 +02:00
Yang Liu 1e771b2496 [RV64_DYNAREC] Added more opcodes (#4411) 2026-09-17 16:30:48 +02:00
Yang Liu 242228de83 [RV64_DYNAREC] Fixed typos in updateflags_pass (#4410) 2026-09-17 16:04:18 +02:00
Zhijin Zeng ae8a2eb85e [RV64_DYNAREC] Optimize aligned REP STOSB with DF=0 (#4407)
Keep DF=1, unaligned path and RCX<8 unchanged.

Use 64-bit stores for the aligned path, reducing the loop overhead for large
byte fills.
2026-09-17 21:40:42 +08:00
Zhijin Zeng 94b4f93540 [RV64_DYNAREC] Hoist max value calculation and use Zbb to eliminate branch for SAT[U]w (#4409)
1. Hoist `ADDIW(reg, max, -1)` out of the loop to reduce instructions. Make SATw
and SATUw take inclusive upper bounds and update all callers accordingly.

2. Use Zbb MIN/MAX instructions to clamp signed and unsigned saturation results,
and eliminate branches.
2026-09-17 21:28:22 +08:00
Yang Liu 92527ded34 [DYNAREC] Added dynablock in_used tracking and removed DYNAREC_PURGE (#4405)
With DYNAREC_CALLRET>1, a callee returns directly into the caller block. If that block is invalidated and its JIT memory reused before all pending returns are done, the returning thread jumps into random data. in_used is now tracked and the deferred free only recycles blocks with in_used==0.
DYNAREC_PURGE and tick tracking were removed, they were marked as legacy and now it's a good time to remove.
2026-09-17 09:32:51 +02:00
ptitSeb b30ad56e97 [WRAPPER] Fix build for older glibc (for #4404) 2026-09-17 09:17:57 +02:00
Yang Liu cc07741a6c [RV64_DYNAREC] Added more LOCK prefix opcodes (#4402)
* [RV64_DYNAREC] Added more LOCK prefix opcodes

* Small fix
2026-09-16 17:08:59 +02:00
forain b40b2f1293 [SIGNAL] Re-raise software-generated fatal signals (#4400) 2026-09-16 13:58:31 +02:00
Yang Liu 5da0996aee [RV64_DYNAREC] Added more LOCK prefix opcodes (#4401) 2026-09-16 13:55:21 +02:00
Yang Liu 3ad88dc2e1 [RV64_DYNAREC] Added more opcodes (#4399) 2026-09-16 11:56:28 +02:00
Zhijin Zeng fef3a9702f [RV64_DYNAREC] Share fast hash between RV64 and PPC64LE backends (#4396)
* [RV64_DYNAREC] Share fast hash between RV64 and PPC64LE backends

Move the fast hash function from the PPC64LE backend into dynablock.c as a
shared helper, `normal_fast_hash`.

RV64 previously had no `ARCH_CRC` defined, so `X31_hash_code` fell back to the
slow byte-by-byte loop on every dynablock validation.

PPC64LE keeps the same algorithm, just routed through the shared helper.

* Change normal_fast_hash to be fallback hash path
2026-09-16 16:50:15 +08:00
Yang Liu 77fdc0bafb [STEAM] Added ondemand SteamUI to save memory (#4397) 2026-09-16 09:02:34 +02:00
Yang Liu f9d58352e9 [CUSTOMMEM] Fixed race between concurrent mmaps silently overwriting guest mappings (#4394)
* [CUSTOMMEM] Fixed race between concurrent mmaps silently overwriting guest mappings

This fixes the unstability of steamwebhelper.

* Try to fix WowBox64 build

* Add some comments
2026-09-15 18:01:51 +02:00
ptitSeb e4eb6dcc3f [BOX32] BOX32 is pretty stable now, so removed most of warning about it 2026-09-15 17:30:12 +02:00
ptitSeb a420817e62 [BOX32][WRAPPER] Added 1 more X11 wrapped function (for #4395) 2026-09-15 17:25:37 +02:00
ptitSeb 793848f551 [CI] Update LLVM used for wine stuffs 2026-09-15 17:12:01 +02:00
Ganyuan Chang 583b5b6e11 [RV64_DYNAREC] Fix nativeflags for high-byte FAST8 operations (#4393)
After 8-bit fast path operations restore the guest GPR layout, the nativeflags handoff always extracts the low byte (AL/CL/DL/BL). Nativeflags therefore uses the wrong byte for high-byte destinations.

Extract the destination byte at its byte offset before passing it to nativeflags.
2026-09-15 10:15:01 +02:00
Yang Liu 23807cdbe7 [RV64_DYNAREC] Added more AVX VPCMP opcodes (#4392) 2026-09-14 12:12:42 +02:00
Yang Liu 8396169efd [RV64_DYNAREC] Added AVX VROUNDPD opcode (#4391) 2026-09-14 11:44:52 +02:00
Yang Liu 384167084a [DYNAREC] Removed a useless const (#4390) 2026-09-14 11:36:05 +02:00
Yang Liu 04f21d33fe [RV64_DYNAREC] Introduced a dynarec version of the UpdateFlags helper function (#4389) 2026-09-14 10:25:13 +02:00
ptitSeb 74276a3ff9 [BOX32][WRAPPER] Try to fix potential issues with dirent inplace shrinking (for #4384) 2026-09-14 10:24:24 +02:00
Yang Liu 36738670ee [LA64_DYNAREC] Added leaf call inline optimization (#4376)
* [LA64_DYNAREC] Added leaf call inline optimization

* Review
2026-09-14 09:20:11 +02:00
Zhijin Zeng c540e82aef [WRAPPER] Fix va_list handling for glib2/gio2/gstreamer log & error functions (#4388)
`CREATE_VALIST_FROM_VALIST` only copies GP register arguments and stack slots,
ignoring XMM register arguments entirely, so any %f in the format string
produced wrong output.

Replace `CREATE_VALIST_FROM_VALIST` with `myStackAlignValist`, which parses the
format string and correctly extracts both integer and floating-point arguments
from the x64 va_list.
2026-09-14 09:19:08 +02:00
Yang Liu 0b689c4bd4 [RV64_DYNAREC] Fixed VAESIMC opcode (#4387) 2026-09-14 09:17:53 +02:00
Yang Liu 64a882ab38 [RV64_DYNAREC] Added non-zvfh fallback path for VCVTPH2PS opcode (#4386) 2026-09-14 09:17:06 +02:00
Yang Liu f7a42e850b Fixed some compilation warnings (#4385) 2026-09-14 09:06:44 +02:00
Zhijin Zeng e5c9d55b8b [WRAPPER] Limit the maximum length of mmap with MAP_NORESERVE to 96GiB on 39‑bit platforms (#4377)
On x86-64 platform, the V8 sandbox attempts to reserve up to ~1.3 TiB of virtual
address space via `mmap(MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE)`, then retries
with progressively smaller sizes (512/256/128/64/32 GiB) if fail.

On 39-bits platform, it will allocates 128GiB of address space, consuming most
of the user-mode address space. This prevents subsequent allocation of the 64GiB
address region required by V8 `PartitionAlloc`.

I set the maximum length of such reservations to 96GiB. Any anonymous
`MAP_NORESERVE` mmap exceeding the limit is rejected with ENOMEM, forcing the V8
sandbox to try a smaller reservation.

The `MAP_NORESERVE` flag is used to distinguish memory requests from the V8 sandbox
or V8 PartitionAlloc and other.
2026-09-14 09:04:11 +02:00
Zhijin Zeng 2c188cfc35 [RV64_DYNAREC] Fix clobbering scratch register for VDPPS 256-bit (#4379)
Hoist scratch register allocations (d0/q2/d1/d2) outside the loop to prevent
exhaustion when vex.l=1.

The original code allocated 3 vector registers per lane iteration, exceeding
the vector registers number limit and causing some vector register aliasing.

Also merge 4 per-lane output masks into one combined mask.
2026-09-14 06:32:09 +08:00
Zhijin Zeng eb3a37a5e6 [RV64_DYNAREC] Fix VADDSUBPD opcode vector implementation (#4378)
Swap ADD/SUB in the RV64 vector implementation, so even lanes subtract and odd
lanes add.

Before:
```
DEST[63:0] := SRC1[63:0] + SRC2[63:0]
DEST[127:64] := SRC1[127:64] - SRC2[127:64]
DEST[191:128] := SRC1[191:128] + SRC2[191:128]
DEST[255:192] := SRC1[255:192] - SRC2[255:192]
```

After:
```
DEST[63:0] := SRC1[63:0] - SRC2[63:0]
DEST[127:64] := SRC1[127:64] + SRC2[127:64]
DEST[191:128] := SRC1[191:128] - SRC2[191:128]
DEST[255:192] := SRC1[255:192] + SRC2[255:192]
```
2026-09-14 06:30:52 +08:00
ptitSeb eb49d3d97f [DYNAREC] Small change on dynablock retry 2026-09-13 18:19:13 +02:00
ptitSeb b4f78a1cea [RCFILE] Added 2 more games profile 2026-09-13 15:26:25 +02:00
ptitSeb e4e5cba58c [DYNAREC] Improved HotPage handling 2026-09-13 14:10:34 +02:00
Yang Liu a83b0accf8 [WRAPPER][BOX32] Wrapped __sched_cpualloc/cpufree (#4381) 2026-09-13 09:57:36 +02:00
Zhijin Zeng c79152cb46 [CORE] Fix some logic errors reported in #4214 (#4271)
1. Preserve `state` across spaces in printf/wprintf stack aligners. A space
inside a format specifier should not reset the parsing state.

2. Initialize and reset the GVariant parser nesting counter (`tmp`) when
entering `a` (array) and `@` (GVariant*) states.

3. Advance `st` only when an argument is actually read from the stack in
`myStackAlignGVariantNew`. Previously `++st` was executed unconditionally,
even for register arguments, causing subsequent stack arguments to be read
from wrong offsets.
2026-09-11 11:11:55 +02:00
forain 5524b62033 [WRAPPER] Check the validity of the path before my_execve (#4371) 2026-09-10 09:57:05 +02:00
Zhijin Zeng a99eed9a38 [ELFLOADER] Suppport R_386_IRELATIVE (#4375)
Initialize GOT[1] and GOT[2] before processing i386 dynamic relocations, so PLT0
has valid elf header and resolver function during IFUNC and IRELATIVE handling.
2026-09-10 09:27:39 +02:00
Yang Liu 1a0a128272 [LA64_DYNAREC] Optimized LEA opcode (#4374) 2026-09-10 09:20:59 +02:00
Zhijin Zeng 92f5a7fe5f [ELFLOADER] Initialize the x86-64 PLT resolver before relocation (#4373)
GOT[0] and GOT[1] are initialized only after the `RelocateElfRELA` function
returns. However, `GOT[0]` and `GOT[1]` may already be required while processing
`R_X86_64_IRELATIVE` inside `RelocateElfRELA`.

This patch always initialize GOT[1] and GOT[2] before processing x86-64 dynamic
relocations, so PLT0 has valid elf header and resolver during IFUNC and IRELATIVE
handling.

Before:
```
     |_ RelocateElf64
     |_ RelocateElfPlt64
     |     |_ JUMP_SLOT strlen
     |     |     |_ *need_resolv = 1
     │     |_ ifunc resolver
     │     |     |_ ifunc resolver call strcmp
     │     |            |_ strcmp call PLT -> GOT[x] not filled -> fallback → PLT[0]
     │     |                  |_ PLT[0]: push [GOT[1]] = 0
     │     |                             jmp  [GOT[2]] = 0
     |     |                                    |_ ERROR
     |     |_ SeedPltResolver64: GOT[1] = head, GOT[2] = pltResolver64
```

After:
```
     |_ RelocateElf64
     |     |_ SeedPltResolver64: GOT[1] = head, GOT[2] = pltResolver64
     |_ RelocateElfPlt64
     │     |_ ifunc resolver
     │           |_ ifunc resolver call strcmp
     │                 |_ strcmp call PLT -> GOT[x] not filled -> fallback → PLT[0]
     │                       |_ PLT[0]: push [GOT[1]] = head
     │                                  jmp  [GOT[2]] = pltResolver64
```
2026-09-09 16:27:10 +02:00
Yang Liu a4bbaa525c [LA64_DYNAREC] Reworked some 16-bit LOCK opcodes (#4372) 2026-09-09 13:54:06 +02:00
Zhijin Zeng e2219d8fac [RV64_DYNAREC] Fix writing read-only page for SHA/AES opcode (#4370)
If `Ex` is memory source operand, not need to write back. If `Ex` pointer to
read-only page, `if (!MODREG) PUTEX_vector(v1, VECTOR_SEW32)` will cause SIGSEGV
error.
2026-09-08 21:54:43 +08:00
ptitSeb 4e5f1806dc [ARM64_DYNAREC] Improved RDSEED / RDPID emulation (for #4368) 2026-09-07 14:49:44 +02:00
ptitSeb ad64e829e5 [INTREP] Improved RDSEED / RDPID emulation (for #4368) 2026-09-07 14:49:24 +02:00
Zane 36d1cd790a [WRAPPER] Fix FTSENT layout mismatch (#4329) 2026-09-07 10:19:55 +02:00
Yang Liu 797bd01859 [LA64_DYNAREC] Added 16-bit LOCK OR opcode (#4367) 2026-09-07 08:48:14 +02:00
Voltrex b5697f4107 [CMAKE] Disable PIE when fixing Box64 load address (#4362)
--image-base does not disable PIE with Clang/LLD, allowing Box64 to
be relocated above the 32-bit address range used by Box32.

Pass -no-pie whenever the fixed Box64 image base is used unless the
target is Android.
2026-09-06 21:01:19 +02:00
Yang Liu b9bd355e12 [RV64_DYNAREC] Added AES and SHA opcodes (#4366) 2026-09-06 13:00:54 +02:00
Yang Liu 7e886595c7 [RV64_DYNAREC] Fixed CALL FAR opcode (#4365) 2026-09-06 12:57:13 +02:00
Yang Liu a4cc147ec4 [RV64_DYNAREC] Added more AVX opcodes (#4364) 2026-09-06 12:54:30 +02:00
Yang Liu 40d820b27f Fixed some compilation warnings (#4363) 2026-09-06 12:51:23 +02:00
Ming Hengqiang fffc39881a [RV64_DYNAREC] Fixed PMULDQ vector path using wrong scratch register on VLEN=128 (#4361) 2026-09-05 09:41:12 +02:00
Zhijin Zeng b9fd03e3a2 [RV64_DYNAREC] Fix clobbering FRM in CVTPD2PS NaN handling (#4360)
The CVTPD2PS fastnan=0 path reused x6 while it held the rounding mode saved by
`sse_setround`. Use x4 to replace x6 in NaN handling so `x87_restoreround` can
restore FRM correctly.
2026-09-05 09:39:32 +02:00
Luke ShortandClaude Opus 5 0d261b6e90 Fix AnyDesk (#4359)
* [WRAPPER] update wrapped functions for AnyDesk

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

* [WRAPPER] fix related but non-fatal wrapping issues for AnyDesk

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

* [WRAPPER] avoid free_sized functions on static builds

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-05 09:38:45 +02:00
Zhijin Zeng 6ff9276b1b [RV64_DYNAREC] Support VZEROUPPER and VZEROALL opcode (#4358) 2026-09-04 23:06:11 +08:00
Yang Liu f21db8d170 [LA64_DYNAREC] Added fastpath for native nofpu calls (#4357) 2026-09-04 10:48:58 +02:00
SignKirigami 5905dc5639 [WRAPPER] Added libcairo.so.2 as one of NEEDED_LIBS for gdk3 (#2136) (#4356) 2026-09-04 10:48:11 +02:00
Yang Liu 49ce9e5bd5 [LA64_DYNAREC] Optimized PDEP/PEXT opcodes (#4355) 2026-09-04 09:39:44 +02:00
Yang Liu 2add381bf7 [LA64_DYNAREC] Optimized fpu cache unloading (#4354)
Perform a linear scan of the jump target and skip the cache unloading for registers that are overwritten before they are used.
2026-09-04 09:19:00 +02:00
Yang Liuandphorcys 1eb97e51a2 [LA64_DYNAREC] Optimized all PCMPSTR opcodes (#4350)
* [LA64_DYNAREC] Optimized all PCMPSTR opcodes

Co-authored-by: phorcys <[email protected]>

* Disable sse4_2 on LoongArch

---------

Co-authored-by: phorcys <[email protected]>
2026-09-04 08:17:00 +02:00
Yang Liu 31106cd00e [RV64_DYNAREC] Added more opcodes (#4353) 2026-09-03 19:26:40 +02:00
Yang Liu e4c9577f32 [DYNAREC] Fixed missing flags sync on truncated blocks (#4351) 2026-09-03 11:39:52 +02:00
Yang Liu e367134e7f [LA64_DYNAREC] Refined illegal opcodes handling (#4349) 2026-09-03 09:26:49 +02:00
Yang Liu a01ded9351 [SIGNAL] Synchronized deferred flags across signal contexts (#4348) 2026-09-03 09:22:21 +02:00
ErickyandClaude Opus 5 0708e6f9fd [WRAPPER] Add missing 32bit libc/libresolv symbols (#4346)
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 09:11:12 +02:00
Luke Short d79d0efad8 Add install bundle option (#4344)
* [BUNDLE] add '--install' option

* [BUNDLE] add '--debug' option

and disable it by default.

Also require '--build' option now so the intent is explicit.

* [CMAKE] add BUNDLE_X86_LIBS options

to automatically install the tarball from the GitHub Release.

* [BUNDLE] support DESTDIR
2026-09-02 22:43:25 +02:00
Zhijin Zeng 4de091016b [CORE] Fix some errors reported in #4214 (#4343)
1. Fix some typos.

2. Add missing `else` for RunFunction.

3. Add missing `used_gtktypeinfo=1`
2026-09-02 09:01:15 +02:00
Zhijin Zeng 65702d61c3 [WRAPPER] Fix some erros reported in #4214 (#4342)
1. `ENGINE_get_first` prototype: `ENGINE *ENGINE_get_first(void);`

2. PASSWD_CHANGEREQ_FUNC prototype:
`typedef int (*LIBSSH2_PASSWD_CHANGEREQ_FUNC)(LIBSSH2_SESSION *session, char **newpw, void **abstract);`

3. `context_type_get` need return value, and it's prototype is
`const char *context_type_get(context_t con);`
2026-09-01 13:35:52 +02:00
Yang Liu 3f74c742c6 [LA64_DYNAREC] Added host_call to arch state (#4340)
* [LA64_DYNAREC] Added host_call to arch state

* [LA64_DYNAREC] Refined host_call arch state with call window offset
2026-09-01 11:50:13 +02:00
Yang Liu fc1f3419a6 [SIGNAL] Refined handling of invalid sigsetsize in syscall_rt_sigaction (#4335)
* [SIGNAL] Refined handling of invalid sigsetsize in syscall_rt_sigaction

* Fixed review
2026-09-01 11:46:44 +02:00
Yang Liu bc19066a29 [WRAPPER] Refined exec family envp wrapping (#4339) 2026-09-01 09:25:35 +02:00
Yang Liu 022a637136 Fixed scanf %m modifier handling (#4337) 2026-09-01 09:17:58 +02:00
Yang Liu ebae9d1db6 [SYSCALL] Added fchdir syscall (#4336) 2026-09-01 09:15:16 +02:00
Yang Liu cd9b0358b3 [WRAPPER] Fixed a rare case of madvise wrapping (#4334) 2026-09-01 09:11:00 +02:00
Luke Short 12636eb321 [CORE] Add MIT license header to all relevant source files (#4287)
to all relevant source files.

Resolves #484
2026-08-31 19:50:21 +02:00
Yang Liu 1e7121e48f [SYSCALL] Fixed getdents wrapping (#4332) 2026-08-31 14:05:04 +02:00
forain 6f9ed4cc1e [SIGNAL] Preserve SA_RESTART semantics in signal() (#4333)
Signed-off-by: forain <[email protected]>
2026-08-31 18:05:07 +08:00
Yang Liu 4e144ee147 [SIGNAL] Fixed FPU state handling (#4331) 2026-08-31 10:53:05 +02:00
Yang Liu c383d0313e [SYSCALL] Handled some rare cases in clone wrapping (#4330) 2026-08-31 10:22:29 +02:00
Yang Liu 1cc0874b0c [SYSCALL] Fixed fcntl wrapping (#4328) 2026-08-31 09:55:04 +02:00
Yang Liu b68905249e [ELFLOADER] Removed p_paddr usage (#4327)
According to ELF specification, `p_paddr` should never be used on systems with virtual memory.

https://www.sco.com/developers/gabi/latest/ch5.pheader.html

> p_paddr
> Because System V ignores physical addressing for application programs, this member has unspecified contents for executable files and shared objects.
2026-08-31 09:44:28 +02:00
Zhijin Zeng f39cedc9c5 [WRAPPER] Fix some argments erros reported in #4214 (#4326)
These functions take variadic arguments instead of a `va_list`.
2026-08-31 09:42:24 +02:00
Yang Liu 16c3d08bb5 [LA64_DYNAREC] Raised SIGFPE on div0, always emit SIGTRAP on INT3 (#4325) 2026-08-31 09:40:09 +02:00
SeeSchloßandYang Liu 0f6603ed42 Add SDL_RenderLogicalToWindow function wrapper (#4308)
* Add SDL_RenderLogicalToWindow function wrapper

* Added missing (generated) changes

---------

Co-authored-by: Yang Liu <[email protected]>
2026-08-31 10:12:10 +08:00
Yang Liu b238f4f1b8 [RV64_DYNAREC] Added preliminary RVV1.0 (vlen>=256) AVX/AVX2 implementation (#4324)
* [RV64_DYNAREC] Added preliminary RVV1.0 (vlen>=256) AVX/AVX2 implementation

Fully tested. Not optimized for performance (yet).

* Fixed CI

* Fixed CI again
2026-08-30 17:59:45 +02:00
Yang Liu 55083ea13d [STEAM] Added a hack to fix the stair-stepping logging issue (#4323) 2026-08-29 21:15:31 +02:00
Yang Liu fa94836a96 [ARM64_DYNAREC] Raised SIGFPE on div0 (#4321)
This is Arm64 DynaRec only for now; other architectures will come later.
2026-08-29 21:00:59 +02:00
Luke ShortandClaude Opus 5 171d7b2144 Fix Lime and Telegram (#4322)
* [WRAPPER] Wrapped missing libX11 extension hooks reported in #1204
* [WRAPPER] Wrapped g_list_copy_deep and g_dbus_connection_call_with_unix_fd_list for #1204
* [WRAPPER] Wrapped the rest of the C11 threads API
* [WRAPPER] Wrapped the zwp_pointer_gesture_swipe_v1 Wayland listener
* [WRAPPER] Fixed g_signal_new with 9 to 14 parameters
* [WRAPPER] Run x86_64 children of g_spawn and GSubprocess under box64
* [WRAPPER] Remove verbose comments

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-29 20:36:45 +02:00
Yang Liu 0b5d30b9a8 [SIGNAL][ARM64_DYNAREC] Emitted SIGTRAP on INT3 regardless of handler state (#4320)
This is Arm64 DynaRec only for now; other architectures will come later.
2026-08-29 19:14:42 +02:00
Yang Liu 4e3bb8861b [ARM64_DYNAREC] Fixed VLDR128/VSTR128 S9 emitter (#4319) 2026-08-29 17:55:17 +02:00
Vaibhav Srivastava 31c8d836fc docs: fix typo priviledge -> privilege (#4318)
Signed-off-by: Vaibhav Srivastava <[email protected]>
2026-08-29 15:59:02 +02:00
Yang Liu 0b0fb69c9f [WRAPPER] Wrapped libc arch_prctl (#4317) 2026-08-29 11:06:18 +02:00
Yang Liu babdc6961f [SYSCALL] Fixed io_getevents and io_setup wrapping (#4316) 2026-08-29 10:03:03 +02:00
Yang Liu 36260684e4 [WRAPPER][SYSCALL] Fixed sched_get/setaffinity wrapping (#4315) 2026-08-29 09:58:12 +02:00
ptitSeb c305b57c6f [ARM64_DYNAREC] Fixed some printer for some speicifc ADD/SUB ocpodes 2026-08-28 15:17:22 +02:00
Yang Liu 96b70f8737 [DYNAREC] Don't truncate registers to 32bits when switching to 32-bit mode (#4312) 2026-08-28 15:16:23 +02:00
Yang Liu e6ddae9f54 [SIGNAL] Don't build signal frame when the guest handler is SIG_DFL or SIG_IGN (#4313)
If the guest program has no handler for a signal (or asked to ignore it), just let the process die from that signal (or ignore it).
This matters because the guest's stack pointer can be garbage at the point of such a signal.
2026-08-28 13:45:25 +02:00
Yang Liu 27fbe43d92 [SYSCALL][BOX32] Added exit_group syscall (#4311) 2026-08-28 13:25:38 +02:00
Yang Liu f79640e527 [DYNAREC][INTERP][BOX32] Fixed SYSCALL and SYSENTER in 32-bit mode (#4310) 2026-08-28 13:03:18 +02:00
Zhijin Zeng 6f6fc3bc25 [WRAPPER] Fix GLib vprintf-family wrappers reported in #4214 (#4309)
GLib vprintf-family wrappers incorrectly treated the guest va_list as variadic
arguments.
2026-08-28 12:23:59 +02:00
Yang Liu 59d8dc6051 [WRAPPER] Fixed open(NULL) handling (#4307) 2026-08-28 10:15:04 +02:00
Zhijin Zeng d36e574be1 [WRAPPER] Fix some errors reported in #4124 (#4306)
1. Add return value of `copy_func` which pointers to new element in openssl.
`typedef void *(*OPENSSL_sk_copyfunc)(const void *);`

2. Initialize other fields of `my_GParamSpecTypeInfo_t`.

3. Track cached `GParamSpecTypeInfo_t` slots independently from source pointers,
and compare `GParamSpecTypeInfo` fields explicitly instead of comparing padding
bytes.
2026-08-28 10:11:13 +02:00
Yang Liu 77964a083f [WRAPPER] Fixed CLONE_VM|CLONE_VFORK handling in clone (#4305) 2026-08-28 10:06:14 +02:00
Yang Liu 944776384a [MMAP] Don't allocate bridge bricks in guest low memory for 64bits guests (#4303)
The guest can MAP_FIXED over low addresses, destroying the bridges living there, and even munmap them. Only allocate the bridges low for 32bits guests, which needs the guest bitness to be detected before the context is created.
2026-08-28 09:20:51 +02:00
Yang Liu d51e72eca8 [SIGNAL] Don't emulate already aligned accesses in SIGBUS special cases (#4302) 2026-08-28 09:03:31 +02:00
Yang Liu 711b07a7d8 [SIGNAL] Die with the signal instead of aborting when the guest handler is SIG_DFL (#4300) 2026-08-28 08:50:22 +02:00
Zhijin Zeng acec20bfc5 [RV64_DYNAREC] Support VPBROADCAST[B/W/D/Q] opcodes (#4294) 2026-08-28 09:30:25 +08:00
Zhijin Zeng aab716ff6e [WRAPPER] Fix some errors reported in #4214 (#4297)
1. Correct variadic argument offsets for `my_g_fprintf` and `my_dbus_message_new_error_printf`.

2. Fix callback bridge reverse lookups in glib2 and libx11.

3. Correct `gdk_window_set_modal_hint` signature.
`void gdk_window_set_modal_hint (GdkWindow *window, gboolean modal)`

4. Add `mq_notify` callback translation for `SIGEV_THREAD` notifications.
2026-08-27 12:31:34 +02:00
Yang Liu 2f7b82bef1 [LA64_DYNAREC] Fixed regressions introduced by commit d69e4a96 (#4296) 2026-08-27 11:30:39 +02:00
ptitSeb 951808acd1 [CI] Fixed NOBOX64 use for WOWBOX64 build and added doc in COMPILE.md 2026-08-27 11:27:37 +02:00
ptitSeb 5b352263af [CI] Use NOBOX64 for WOWBOX64 build 2026-08-27 11:06:03 +02:00
ptitSeb 7e98945d1d [CMAKE] Added NOBOX64 to avoid building main BOX64 binary (usefull for wowbox64 build) 2026-08-27 11:04:47 +02:00
Zhijin Zeng 90b02b9a41 [WRAPPER] Fix some errors reported in #4214 (#4295)
1. `XFixesExtensionInfo` and `XRenderExtensionInfo` is 24‑bytes in size.

2. The internal `error_string` helper in libXext has a return type of `char *`.

3. Passing an `i386_ifconf_t *` to ioctl results in read overflow.

4. Streams may be reused, so unwrap must still be performed in the `xxx_end`
functions of libz and liblzma.
2026-08-26 13:52:54 +02:00
Zhijin Zeng dc57589aac [CORE] Fix some errors reported in #4214 (#4292)
1. In `wrapVulkanSymbol`, the key should be `rname`.

2. In `isNativeCall32`, `a1` holds the address of the GOT entry rather than the
actual jump target address stored within it.

3. Reset `clean_sz` and `clean_cap` after freeing `clean_ups`, so later `atexit`
allocate a new list instead of writing through NULL.

4. Clear CPU mask bits starting at MAXCPU.
2026-08-25 12:58:20 +02:00
ptitSeb 1f7ff4b968 Revert "[SYSCALL] Align io_uring epoll events (#4283)" (#4291)
This reverts commit 9cd1d38751.
2026-08-25 10:00:44 +02:00
Zhijin Zeng 9cd1d38751 [SYSCALL] Align io_uring epoll events (#4283)
This patch addresses an issue where repeated `epoll_pwait` calls cause a hang
upon executing `copilot --version`.

While `epoll_wait` family functions perform alignment handling for `epoll_event`,
the `epoll_event` passed for `IORING_OP_EPOLL_CTL` submitted through `io_uring_enter`
lacks such alignment handling. This results in failures when `io_uring` operates in
conjunction with `epoll`.

This patch does the following work:

1. Rewrite the `io_uring_setup` syscall handler to record uring fd state.

2. Track virtual addresses of `IORING_OFF_SQ_RING` and `IORING_OFF_SQES` of the
uring fd when mmap is performed.

3. Rewrite the `io_uring_enter` syscall handler. Prior to the `io_uring_enter`
syscall, align `epoll_event` if the operation is `IORING_OP_EPOLL_CTL`, restore
and clean up after the syscall completes.
2026-08-25 09:39:09 +02:00
Luke Short 91b7fa7eea [CORE] Fix possible buffer overflow for box64rc path (#4288)
Resolves #724
2026-08-24 22:37:38 +02:00
airidosas252 ec1d5a6ac2 [WINE] Add shared CPU feature list for WowBox64 (#4286) 2026-08-24 21:09:29 +02:00
Yang Liu a793cd52c2 [DYNAREC] Added preliminary interblocks deferred flags elimination (#4284)
* [DYNAREC] Added preliminary interblocks deferred flags elimination

* Fix compilation
2026-08-24 16:02:17 +02:00
Chi-Kuan Chiu 9e8d8193dc [ARM64_DYNAREC] Fix memory corruption in unaligned LOCK CMPXCHG8B/16B (#4280)
Since x5 is guaranteed to be 0 after line CBNZw_MARK2(x5), this
incorrectly zeroed the first byte.

Changed x5 to x2 to safely write back the original
lowest byte fetched by the initial LDP.
2026-08-24 10:24:18 +02:00
Mikura Kyouka d50beea87b [RCFILE] Fixed a game launcher profile (#4282) 2026-08-24 08:49:04 +08:00
Zhijin Zeng 455bc1c4a2 [RV64_DYNAREC] Support PHSUBD and PEXTRB opcode (#4279) 2026-08-24 08:47:33 +08:00
Zhijin Zeng 76fda7910e [ELFLOADER] Support versioned data symbols (#4274)
This patch is to fix `sys_siglist` not found error reported by dingtalk.
2026-08-21 20:32:15 +02:00
leonpano2006andClaude Opus 4.8 67e8c97ca1 [BOX32] Revive fwprintf/vfwprintf/vwprintf wrappers (#4278)
Parked in #if 0 since the W32 renames, table entries commented out, so
32-bit programs using them abort with symbol-not-found. Reworked to the
current pattern following my32_wprintf; FILE args use the S conversion
types like fprintf/vfprintf. Existing wrapper types only, no regen.


Claude-Session: https://claude.ai/code/session_01XmTHuyWNGcGnG3o55fzoDV

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-20 21:24:12 +02:00
Zhijin Zeng 64367de6bf [WRAPPER] Wrapper libopus.so library (#4277)
libopus.so is used by dingtalk app.
2026-08-20 21:01:48 +02:00
Zhijin Zeng 060b5d6bdb [WRAPPER] Wrapper some libc symbols (#4275)
1. pthread_mutexattr_setrobust_np
2. pthread_mutex_consistent_np
3. sys_siglist

These symbols are used by libapr.so in dingtalk.
2026-08-20 20:59:41 +02:00
Zhijin Zeng 6d039e5df1 [WRAPPER] Add some symbols in gnutls (#4276)
1. gnutls_certificate_set_verify_function
2. gnutls_session_set_verify_function

These symbols are used by dingtalk_dll.so in dingtalk.
2026-08-20 19:52:39 +02:00
Yang Liu b32ea75869 [WRAPPER] Refined gtk wrapping for #4251 (#4272) 2026-08-20 09:11:58 +02:00
Yang Liu 499d038626 [MEM] Reduced autocrc overhead by merging guest page protections (#4270)
* [MEM] Reduced autocrc overhead by merging guest page protections

On non-4K hosts, several 4 KiB guest pages share one host page. A writable neighboring guest page previously forced the entire host page into NEVERCLEAN mode, introduces huge overhead on many games.

This PR tracks guest page permissions and DynaRec protections separately. Once all writable guest pages within a host page are covered by DynaRec, protect the host page and rebuild its blocks without autocrc.
2026-08-20 09:41:56 +08:00
Zhijin Zeng 7fbbcd3468 [RV64_DYNAREC] Support VMOVMSKPS opcode (#4269) 2026-08-19 21:07:54 +02:00
Yang Liu 4aa4f6f70d [WRAPPER] Wrapped more symbols for libatspi and libdbus (#4268) 2026-08-19 21:05:50 +02:00
Yang Liu d1bb1d1e05 [MEM] Optimized box_mmap for performance (#4267)
find47bitBlock is slow, try mmap first and query mapallmem rbtree on failures only.
2026-08-18 20:20:08 +02:00
Yang Liu 9e13288ed2 [DYNAREC] Spill RIP/RSP before LinkNext in case a signal arrives in C (#4266) 2026-08-18 20:18:19 +02:00
Yang Liu 72cd18a8bc [WRAPPER] Wrapped libnotify (#4265) 2026-08-18 20:16:38 +02:00
Zhijin Zeng caf201fec9 [WRAPPER] Fix some logic errors in #4214 (#4264)
1. Add Xt returned error-handler conversion.

2. Fix FUSE stat and mode argument conversions.

3. Fix llrintl return values.

4. Add the `user_data` argument to PCRE2 callouts.

5. Add the NSS UCS2-to-UTF8 callback wrapper.

6. Add the whence argument to TIFF seek callbacks.
2026-08-18 20:15:04 +02:00
Zane 2bb936b5fd [WRAPPER] Handle '#' format in myStackAlign* (#4263) 2026-08-18 20:11:00 +02:00
Zhijin Zeng d2df252722 [CORE] Fix XkbNamesRec in-place conversion reported in #4214 (#4262)
1. Pack `radio_groups` through `XID_32*` during shrink, use the guest's 4-byte
stride instead of the native 8-byte XID stride.

2. Save `num_rg` and convert keys before expanding overlapping fields, because
the enlarged `indicators` overwrite the corresponding 32-bit source fields.
2026-08-18 20:07:22 +02:00
Zane bdc7138c7c [BUNDLE] Add libgfortran5 and libquadmath0 (#4254) 2026-08-18 20:04:59 +02:00
Zhijin Zeng 023d96ec17 [CORE] Fix some logic errors reported in #4214 (#4261)
1. `||` has higher precedence than `?:`, TI bit locates at bit2.

2. `ED` is a `reg64_t *` and it gets scaled by `sizeof(reg64_t)`.

3. Use `rex.w?7:3` to whether address is aligned.
2026-08-18 19:54:19 +02:00
Yang Liu db05d0e664 [RV64_DYNAREC] Refined safeflags and df emulation (#4260) 2026-08-17 20:27:45 +02:00
Yang Liu 777af102a5 [PERFMAP] Fixed a typo (#4259) 2026-08-17 20:27:01 +02:00
Yang Liu 2598e8c7e8 [RBTREE] Added rb_find_free_range to speedup box64_mmap (#4258) 2026-08-17 20:25:15 +02:00
Yang Liuandphorcys ba23a5e8e2 [LA64_DYNAREC] Optimized SHA256 opcodes (#4256)
Co-authored-by: phorcys <[email protected]>
2026-08-17 20:22:57 +02:00
Zhijin Zeng e852f2539f [WRAPPER] Fix some logic errors reported in #4214 (#4257)
1. `vector_popn_del_##name`: use MIN(vsize, n) for n, not MAX(vsize, n).

2. png malloc_fn need return value.

3. `pa_context_set_default_sink` series functions need return value.

4. The callback of `SDL_DelHintCallback` is guest callback, can't use
`reverse_Hint_Fct` here.

5. `selinux_get_callback` need `E`.

6. `my_SEC_PKCS12CreateExportContext` need return value.
2026-08-17 20:21:35 +02:00
Yang Liu d69e4a9684 [LA64_DYNAREC] Added SIMD registers preload and added SS/SD renaming (#4255) 2026-08-17 20:17:06 +02:00
Yang Liu f204ae6900 [LA64_DYNAREC] Fixed VCVTTPD2DQ opcode (#4253) 2026-08-17 09:45:12 +02:00
Yang Liu 6271ae2fd3 [LA64_DYNAREC] Refined up32 tracking for nativeflags (#4252) 2026-08-17 09:44:06 +02:00
Yang Liu b38a33c00d [DYNAREC] Small optimization to strongmem emulation (#4249) 2026-08-14 20:49:01 +02:00
Zhijin Zeng 1227cf2e6b [CORE] Fix some UAFs and OOB reported in #4214 (#4246) 2026-08-14 20:39:04 +02:00
Zhijin Zeng ed8c6b2e82 [CORE] Fix some panic errors reported in #4214 (#4248)
1. `dlerror` may return NULL.
2. `sqlite3_database_file_object` may return NULL or it's `pMethods` may be NULL.
3. The parameter of `libusb_free_transfer` may be NULL.
4. The parameter of `utimensat` may be NULL.
2026-08-14 20:27:51 +02:00
Yang Liu 2969b05414 [PROFILE] Optimized Wukong profile (#4247) 2026-08-14 20:11:00 +02:00
Yang Liu af7eb3177f [LA64_DYNAREC] Optimized LOCK CMPXCHG opcode (#4245) 2026-08-14 20:07:59 +02:00
Yang Liu 3a2f1727c3 [WRAPPER] Fixed g_child_watch_add_full wrapping (#4244)
* [WRAPPER] Fixed g_child_watch_add_full wrapping

Fixed latest Linux Steam

* Fixed game launching
2026-08-14 18:43:04 +08:00
Zhijin Zeng ceea1465ab [RV64_DYNAREC] Support some VBROADCAST opcode (#4241) 2026-08-14 09:02:00 +08:00
Yang Liu 750a8775b9 [RV64_DYNAREC] Fixed more flags emulation issues (#4243) 2026-08-13 21:10:46 +02:00
Yang Liu ff1771d134 [RV64_DYNAREC] Fixed scalar CVTTPS2DQ fastnan=0 handling (#4242) 2026-08-13 21:09:25 +02:00
Zhijin Zeng 64d2204635 [WRAPPER] Fix UAF for gpgme_data_new_from_cbs reported in #4214 (#4240)
`gpgme_data_release` is invoked without explicitly passing `cbs`. As `cbs`
reside inside a union, fetching the `cbs` is a bit complicated, so no cleanup
helper is provided.

In practice, there are probably few cbs instances, analogous to `cbs->release`
that only has five available slots.

`gpgme_data_new_from_cbs` in:
https://github.com/gpg/gpgme/blob/master/src/data-user.c#L99
2026-08-13 21:05:53 +02:00
Yang Liu 8ed77f3d93 [RV64_DYNAREC] Fixed SF computation of MUL opcodes (#4239) 2026-08-12 19:28:00 +02:00
Yang Liu b5108ce468 [NON4K] Disabled the 64KiB aligned check (#4237) 2026-08-12 18:09:31 +02:00
Yang Liu fb73285312 [RV64_DYNAREC] Fixed some rotate opcodes (#4238) 2026-08-12 17:48:40 +02:00
Zhijin Zeng 60693dc374 [RV64_DYNAREC] Support ADCX opcdoe (#4234) 2026-08-12 23:31:40 +08:00
Yang Liu 2617c97492 [RV64_DYNAREC] Refined more fastnan=0 handling (#4236) 2026-08-12 16:55:00 +02:00
Zhijin Zeng 3c6704a909 Fix some UAF errors report in #4214 (#4228)
* [FIX] Fix potential UAF for my_pthread_cond_destroy_old reported in #4214

* [WRAPPER] Fix UAF for ber_sockbuf_add_io reported in #4214

`ber_sockbuf_add_io` only stores the raw pointer to Sockbuf_IO rather than
copying the structure contents. See it in:

https://github.com/delphij/openldap/blob/master/libraries/liblber/sockbuf.c#L201

Five my_sockbuf_io_t structs are preallocated to avoid heap allocation. An error
occurs when the pool runs out.

No thread safety guarantees.

* [WRAPPER] wrapper ber_sockbuf_remove_io

* [WRAPPER] Add reference count for my_sockbuf_io_ref_A
2026-08-12 15:31:49 +02:00
Yang Liu 554b84068b [MEM] Fixed a typo in box_mmap (#4235) 2026-08-12 13:43:17 +02:00
Yang Liu d74598aaa8 Revert "[LA64_DYNAREC] Speed up crc validation (#4178)" (#4233)
This reverts commit e0ae94d742.
2026-08-12 12:19:01 +02:00
Yang Liu 5b3259491b [NON4K] Fixed wine prefix creation (#4232) 2026-08-12 09:41:35 +02:00
Yang Liu 6fec414a72 [LA64_DYNAREC] Inlined a few common used C fuctions (#4227)
50% faster in dhrystone benchmark.
2026-08-12 09:40:21 +02:00
Yang Liu 80e10e696a [RV64_DYNAREC] Disable flags fusion for all the shift/rotate on CL opcodes (#4231)
* [RV64_DYNAREC] Disable flags fusion for all the shift/rotate on CL opcodes

* [RV64_DYNAREC] Refined safeflags support for those opcodes too
2026-08-11 20:47:45 +02:00
Yang Liu 9f3671b8ec [LA64_DYNAREC] Split la64_00.c to speedup compilation (#4230) 2026-08-11 17:41:18 +02:00
Yang Liu 3601698aa7 [DYNAREC] Removed the gdb backtrace feature for trace build (#4229) 2026-08-11 13:11:31 +02:00
Zhijin Zeng 83a9d67e15 [RV64_DYNAREC] Support VMOVDQU opcode (#4224) 2026-08-11 08:15:53 +02:00
Yang Liu 0b9b6322de [DYNAREC] Hard reset x87 state in EMMS (#4226) 2026-08-10 10:29:16 +02:00
Yang Liu 199f00ebff [WRAPPER] Used a private envp copy for BOX64/86_ARG0 in posix_spawn (#4225) 2026-08-10 09:58:53 +02:00
Zhijin Zeng d6806f0ecc [WRAPPER] Fix missing parameter (#4223) 2026-08-10 09:06:06 +02:00
Zhijin Zeng e8b1004112 [ELFLOADER] Fix typo of numDynamic (#4222)
The outermost loop traverses the PHEntries array, and should use numPHEntries
for boundary limits.
2026-08-10 09:04:21 +02:00
ptitSeb 2595c1e98f [CI] This should fix ANDROID & TERMUX build 2026-08-09 15:03:30 +02:00
ptitSeb 5847f2f193 [WRAPPER][VULKAN] Added a few more vulkan extensions 2026-08-09 15:01:43 +02:00
ptitSeb 303bceba3f [WRAPPER] Added fake libmimalloc with some wrapping (for BeamNG Drive v0.39+) 2026-08-09 14:22:52 +02:00
Yang Liu 1cb3a71c05 [WRAPPER] Fixed wrapping of g_initable_new (#4221) 2026-08-09 10:37:33 +02:00
Yang Liu 09124eb6ef [ARM64_DYNAREC] Addressed more issues reported in #4214 (#4220)
* [ARM64_DYNAREC] Addressed more issues reported in ptitSeb#4214

* review
2026-08-09 09:46:08 +02:00
Yang Liu 78bf553c62 [LA64_DYNAREC] Addressed more issues reported in #4214 (#4219) 2026-08-09 00:21:12 +02:00
Yang Liu da05e01235 [RV64_DYNAREC] Addressed more issues reported in #4214 (#4218) 2026-08-08 16:14:57 +02:00
ptitSeb e809d29035 [ARM64_DYNAREC] Push/Pop SIMD scratch register when calling a C function (should help #4065 and #4206) 2026-08-08 16:07:53 +02:00
airidosas252 d691d07bd9 [OS] Fix FLAGM/FLAGM2 extension detection (#4217) 2026-08-08 14:57:45 +02:00
Yang Liu b552ab5f8f [RV64_DYNAREC] Refactored deferred flags (#4180)
* [RV64_DYNAREC] Refactored deferred flags

* [RV64_DYNAREC] Refactored MUL opcodes
2026-08-08 14:34:20 +02:00
ptitSeb c3294588f9 [WRAPPER] Fixed PANIC_2, PANIC_3, PANIC_4, PANIC_5, PANIC_6 and UAF_2 from #4214 2026-08-08 14:32:30 +02:00
Yang Liu 73e3a97009 [LA64_DYNAREC] Added SS/SD/AVX upper-lane tracking (#4145) 2026-08-08 13:44:36 +02:00
ptitSeb 986846bb7c [INTERP] fixes PANIC_1 from #4214 2026-08-08 11:33:58 +02:00
Yang Liu 43acf32c85 Addressed some wrapping issues report in #4214 (#4215) 2026-08-08 09:57:21 +02:00
Zhijin Zeng e99ca51299 [WRAPPER] Fix my_readlink (#4212)
1. `readlink` does not append a null at the end, so strncpy can't be used.

2. The `buf` may not end with a null, so strstr and strcmp also can't be used.

3. Concatenating `cwd` and `path` is incorrect, which get a string like
`/home/xx/proc/778/exe`. The correct approach is to concatenate `cwd` with the
first string in `cmdline`.

4. Support `box64 test_app`, which is actually a relative path but does not
start with a dot in `cmdline`.
2026-08-07 13:44:43 +02:00
Zhijin Zeng e51e9c84a3 [WRAPPER] Fix typo of my_wl_touch_listener_down (#4213)
An extra parameter `p` has been added to the parameter list.
2026-08-07 13:06:14 +02:00
Yang Liu 9cf3ceaa86 [TLS] Added full support for CLONE_SETTLS (#4209)
* [TLS] Added full support for CLONE_SETTLS

* review
2026-08-07 11:11:35 +02:00
e0d9d9be29 Fix program_invocation_short_name when argv[0] has no '/' (#3972)
my_program_invocation_short_name (and my___progname) were computed as
strrchr(box64->argv[0], '/') + 1. When argv[0] contains no '/', strrchr
returns NULL, and NULL + 1 yields (char*)1 — an invalid pointer. Guest
code that reads program_invocation_short_name / __progname then
dereferences it and crashes (e.g. a std::string ctor doing strlen((char*)1)).

This triggers when a process is exec'd with a bare argv[0] (no path), such
as a renamed fork-server child, and shows up as a SIGSEGV in the forked
child that does not reproduce when argv[0] is a path.

Match glibc: with no '/', the short name is the whole argv[0].

Co-authored-by: UserGreen <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-07 10:26:56 +02:00
Yang Liu e13e3cb1f2 [RCFILE] Added dota2 profile (#4211)
* [RCFILE] Added dota2 profile

* In game requires strongmem=1
2026-08-07 10:25:56 +02:00
Yang Liu 491ab0e304 [NON4K] Added fake 4k protection tracking (#4207)
* [NON4K] Added fake 4k protection tracking

Somehow, The Chromium team decided to use getrlimit to probe the canary pages:

https://chromium.googlesource.com/chromium/src/+/refs/tags/146.0.7680.179/base/memory/protected_memory_posix.cc#45

This PR adds a manually 4k page protection tracking, and fake the protection probing by wrapping getrlimit.

* How did I not push this.
2026-08-07 09:18:09 +02:00
Yang Liu 0e9d41ce15 [NON4K] Loose a check in 4k emulation (#4208)
When MAP_ANONYMOUS is present, mmap() ignores fd.
2026-08-07 09:05:32 +02:00
Yang Liu fa5fbe6acd [WRAPPER] Fixed eglDebugMessageControlKHR wrapping (#4205) 2026-08-07 08:55:11 +02:00
Zhijin Zeng ba373ab4b3 [WRAPPER] Fix strlcat and strcpy corn cases (#4204) 2026-08-06 15:46:47 +02:00
Zhijin Zeng 8ee669331e [RV64_DYNAREC] Fix typo of emit_test32c function name (#4203) 2026-08-06 21:44:19 +08:00
Yang Liu 98459539dc [LIBRARIAN] Fixed weak symbol resolve order (#4201) 2026-08-06 15:43:06 +02:00
Yang Liu 607c22d22a [RCFILE] Added Linux cs2 profile (#4202) 2026-08-06 14:07:27 +02:00
Yang Liu 5e5e598a6b [TLS] Resize TLS after dlopen (#4200) 2026-08-06 14:00:22 +02:00
Yang Liu 62cb8170cc [STEAM] Refined pressure vessal emulation for Protontricks (#4199) 2026-08-06 11:20:16 +02:00
Yang Liu 39d0b82094 [STEAM] Prefer steam runtime libs over box64 stock ones (#4198) 2026-08-06 11:19:13 +02:00
Yang Liu fa6868c5bd [WRAPPER] Fixed a typo in pangoft2 wrapper (#4197) 2026-08-06 10:05:19 +02:00
Yang Liu 5ca4b91e00 [DYNAREC] Reset jumptable entry when an alternate is added (#4196) 2026-08-06 09:32:36 +02:00
Yang Liu 5d881fd59d [ELFLOADER] Fixed RELRO relocation again (#4195) 2026-08-05 17:19:36 +02:00
Yang Liu cec0f61e0e [SIGNAL] Preserved previous handlers, flags, masks, restorer, and alternate-stack state (#4194)
This fixed Black Myth Wukong again, after a long time since it was partially broken.
2026-08-05 14:25:37 +02:00
Zhijin Zeng b277c76d6d [RV64_DYNAREC] Fix error for ANDN and BZHI opcode without zbb (#4193) 2026-08-05 20:17:30 +08:00
Zhijin Zeng 5bbafe7562 [RV64_DYNAREC] Add qNaN handle for ROUNDPD (#4192) 2026-08-05 20:16:30 +08:00
Yang Liu ddd3bd602f [WRAPPER][ENV] Removed crashhandler handling completely (#4191) 2026-08-05 12:43:04 +02:00
Zhijin Zeng 5afc665420 [RV64_DYNAREC] Fix RDTSC and RDTSCP (#4190) 2026-08-05 10:29:45 +02:00
Zhijin Zeng b63f650694 [CORE] Eliminate compile warnings (#4155)
1. `vasprintf` can return a negative value and `buff` may be NULL.

2. The `events` argument in `epoll_pwait` must not be NULL.

3. The size of `val.f.q` is 64 bits.
2026-08-05 10:22:08 +02:00
Yang Liu 61d01a4c2c [PAGESIZE] Fixed Proton support and ported elfloader to Box32 (#4189)
* [PAGESIZE] Fixed Proton support and ported elfloader to Box32

* Refined proton support
2026-08-05 09:10:36 +02:00
Yang Liu 3c670efe6f [MMAP] Fixed wine mappings on 16K hosts (#4187)
Wine works!
2026-08-04 16:46:23 +02:00
Yang Liu 55ed7e9edb [ELFLOADER] Added support for BIND_NOW dynamic tags (#4186) 2026-08-04 15:21:49 +02:00
Yang Liu 9c11c5671c [WRAPPER] Wrapped madvise for non4k pagesize systems (#4185)
* [WRAPPER] Wrapped madvise for non4k pagesize systems

For now, only MADV_DONTNEED is handled by fallbacking to a plain memset on unaligned cases.

* [WRAPPER] Handling unaligned mprotect too

* review
2026-08-04 14:11:13 +02:00
Yang Liu 5656decbde [MMAP] Fixed 4k mmap canary pages handling (#4184) 2026-08-04 12:49:13 +02:00
Yang Liu 1b79a0c060 [PAGESIZE] Emulated 4k pagesize for better compatibility (#4183) 2026-08-04 12:02:11 +02:00
Yang Liu 0db8df7757 [ELFLOADER] Preserved overlapping ELF segments (#4182)
If two ELF segments share the same page on 16K page size systems, do not replace that page with an anonymous fixed mapping, because that would erase data from the first segment. Keep the existing page, map the remaining part from the file, and copy the overlapping bytes into place. Load mappings with temporary write permission, then restore their final ELF protections after initialization.

Fixes 16K page-size support and the regression introduced by b5066f8a. Helps claude running on 16KiB page size systems.
2026-08-04 08:58:44 +02:00
Zane 8ef7ef3209 [ELFLOADER] Fix GNU RELRO applied too early for static binaries (#4181) 2026-08-04 08:57:33 +02:00
ptitSeb 372739d07f [WRAPPER][WAYLAND] Added 2 listener to waylandclient 2026-08-03 19:10:50 +02:00
ptitSeb 34f949bf5d [WRAPPER][BOX32] Added 1 more wrapped function to libogg 2026-08-03 19:01:01 +02:00
Yang Liu dd9743513e [RV64_DYNAREC] Removed a hack on MOVAPS (#4179) 2026-08-03 16:16:32 +02:00
Yang Liu f6617364cd [RV64_DYNAREC] Optimized rotate opcodes (#4169)
* [RV64_DYNAREC] Optimized rotate opcodes

* [RV64_DYNAREC] Optimized SAR opcode

* [RV64_DYNAREC] Extended RCL/RCR emitter to 64-bit

* [RV64_DYNAREC] Fixed RCL/RCR emitter CF ordering

* [RV64_DYNAREC] Fixed scratch conflicts
2026-08-03 15:17:36 +02:00
Yang Liu b5d45778c4 [ELFLOADER] Mapped unaligned segments from file when vaddr and offset share page offset (#4160) 2026-08-03 15:12:49 +02:00
Yang Liu 064c9222ed [INTERP] Refined canonical NaN handling for RISC-V (#4166) 2026-08-03 12:34:30 +02:00
Yang Liu 392502fd11 [RV64_DYNAREC] Refined many fastnan=0 handling (#4165)
* [RV64_DYNAREC] Refined many fastnan=0 handling

* [RV64_DYNAREC] Refined MULPS fastnan=0 handling

* [RV64_DYNAREC] Refined VSQRTPD fastnan=0 handling

* [RV64_DYNAREC] Refined VCVTPD2PS fastnan=0 handling

* [RV64_DYNAREC] Refined SS opcodes fastnan=0 handling

* [RV64_DYNAREC] Refined more fastnan=0 cases

* [RV64_DYNAREC] Fixed HSUBPS opcode

* [RV64_DYNAREC] Refined fastnan for more opcodes

* [RV64_DYNAREC] Refined VADDSUBPS opcodes

* [RV64_DYNAREC] Refined ROUNDSS

* [RV64_DYNAREC] Refined VCVTPD2PS fastnan=0 handling
2026-08-03 12:02:06 +02:00
Yang Liu b5066f8ab4 [ELFLOADER] Use host page size instead of p_align for mapping ranges (#4158)
* [ELFLOADER] Use host page size instead of p_align for mapping ranges

`p_align` only requires `p_vaddr` and `p_offset` to be congruent modulo `p_align`; segment starts need not be `p_align`-aligned. A `p_align` of 16 KiB on a host with 4 KiB pages is therefore perfectly legal. The loader, however, used `p_align` as the page mask when computing mapping and protection ranges, which makes the writable segment's range extended into pages belonging to executable code in my case.

* remove useless guard
2026-08-03 11:55:38 +02:00
Yang Liu e0ae94d742 [LA64_DYNAREC] Speed up crc validation (#4178) 2026-08-03 09:42:02 +02:00
Jim Huang bd47c3da04 [ARM64_DYNAREC] Skip dead scalar SSE upper-lane preserve (#4143)
This tracks liveness for the dead upper lanes of the low XMM registers
separately from whole-register XMM liveness: an upper-64 lane for the
scalar-double ops and an upper-96 lane for the scalar-single ops. Scalar
operations mark their operands as not genuinely reading those upper bits,
while barriers and unknown exits keep the conservative all-needed
behavior.

Use that liveness in the ARM64 F2 0F scalar-double lowering to compute
SQRTSD, ADDSD, MULSD, SUBSD, and DIVSD directly in the destination when
the destination upper-64 is proven dead, and in the F3 0F scalar-single
lowering for SQRTSS, ADDSS, MULSS, SUBSS, and DIVSS when the destination
upper-96 is proven dead. The existing preserve path remains the fallback
for live or unknown upper lanes and for FASTNAN-disabled paths. MOVSS
store and the other scalar-single ops mark their low-32 operands so a
stored scalar result does not pin the upper lane live (mirroring MOVSD
store, which was the difference that let the scalar-double path fire
while the scalar-single one did not).

Benchmark: static x86 benchfloat (LINPACK) on an Ampere eMag, n=9
core-pinned runs, BOX64_DYNACACHE=0 to defeat the on-disk dynarec
cache, parent e3161999c built as the "before". Median KFLOPS:

  double -O2 (scalar-double path)
    SAFEFLAGS=1 : 637,631.540 -> 700,135.472   +9.8%   (MAD 226.468)
    SAFEFLAGS=0 : 765,920.767 -> 853,745.312   +11.5%  (MAD 936.058)
  single -O2 (scalar-single path)
    SAFEFLAGS=1 : 513,127.344 -> 611,984.438   +19.3%  (MAD 264.312)
    SAFEFLAGS=0 : 566,161.312 -> 696,077.312   +23.0%  (MAD  65.313)

Host: Ampere eMag; 1 socket x 32 cores x 1 thread; up to 3.0 GHz; Arm64
Linux v6.8.0.
2026-08-03 09:31:25 +02:00
Yang Liu bae1de053e [ELFLOADER] Added support for read-only after relocation (#4150)
RELRO sections (e.g. .got and .got.plt) are read-only after resolved relocations. This PR prevents unnecessary always_test blocks created on 16K page size systems by following this semantics.

Example sections:
```
  ELF headers and constants     R
  .text and .plt                R-X
  .got and .got.plt             RW during relocation (PT_GNU_RELRO)
  ```
2026-08-03 09:20:22 +02:00
Yang Liu 1058aae561 [WRAPPER] Wrapped at_quick_exit/quick_exit (#4159) 2026-08-03 09:19:46 +02:00
Zhijin Zeng c569c55494 [RV64_DYNAREC] Fix HADDPS NaN issue (#4149)
RISC‑V floating‑point operations produce a default quiet‑NaN of 0x7fc00000,
while x86‑64 defaults to 0xffc00000.
2026-08-03 09:17:52 +02:00
ptitSeb 744e2bb4ec Start of a new dev. cycle 2026-08-03 09:16:10 +02:00
2342 changed files with 50634 additions and 13267 deletions

No files matched your search

+21 -4
View File
@@ -37,7 +37,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64]
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64, ARM64EC]
type: [Release, Trace, StaticBuild, Box32]
exclude:
- platform: ANDROID
@@ -56,6 +56,12 @@ jobs:
type: StaticBuild
- platform: WOW64
type: Box32
- platform: ARM64EC
type: Box32
- platform: ARM64EC
type: Trace
- platform: ARM64EC
type: StaticBuild
- platform: ANDROID
type: Trace
- platform: TERMUX
@@ -95,6 +101,9 @@ jobs:
- platform: WOW64
os: ubuntu-22.04-arm
- platform: ARM64EC
os: ubuntu-22.04-arm
runs-on: ${{ matrix.os }}
container:
image: ${{ matrix.image || '' }}
@@ -195,9 +204,17 @@ jobs:
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
elif [[ ${{ matrix.platform }} == 'WOW64' ]]; then
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
export LLVM_MINGW_VERSION=20260311
export LLVM_MINGW_VERSION=20260616
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
elif [[ ${{ matrix.platform }} == 'ARM64EC' ]]; then
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-DARM64EC=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
export LLVM_MINGW_VERSION=20260616
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
@@ -244,7 +261,7 @@ jobs:
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3 libzydis-dev
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON" >> $GITHUB_ENV
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON -DBAD_SIGNAL=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-powerpc64le-linux-gnu cmake make python3 libzydis-dev
else
+1 -1
View File
@@ -20,7 +20,7 @@ These use cases are **permitted** when making a contribution with the help of AI
- Formatting code for consistency and readability (but do not overload code with comments)
- Completing code segments based on established patterns
- Drafting documentation for project components with which the contributor is already familiar
- Writting Wrappers Callback handling and/or wrappers structures conversion when needed
- Writing Wrappers Callback handling and/or wrappers structures conversion when needed
AI-generated code that has undergone extensive human editing may be accepted, provided you (1) fully understand the AI's initial output, (2) can debug any issues independently (with or without further AI assistance), and (3) are prepared to discuss it directly with human reviewers.
+171 -109
View File
@@ -5,6 +5,7 @@ cmake_policy(SET CMP0065 NEW)
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
option(NOBOX64 "Set to ON to NOT build the main box64 binary (usefull for building box64 dll only)" ${NOBOX64})
option(RPI3ARM64 "Set to ON if targeting an RaspberryPI3 device with multiarch arm64 and armhf" ${RPI3ARM64})
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
option(RPI5ARM64 "Set to ON if targeting an RaspberryPi5 device with multiarch arm64 and armhf" ${RPI5ARM64})
@@ -44,12 +45,14 @@ option(BAD_PKILL "Set to ON to activate the workaround for incoherent pthread_ki
option(SW64 "Set ON if targeting an SW64 based device" ${SW64})
option(CI "Set to ON if running in CI" ${CI})
option(WITH_MOLD "Set to ON to use with mold" ${WITH_MOLD})
option(BOX32 "Set to ON to add Linux 32bits support (experimental, do not use)" ${BOX32})
option(BOX32 "Set to ON to add Linux 32bits support" ${BOX32})
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(ARM64EC "Set to ON to build Box64EC PE DLL module (no emulation yet)" OFF)
option(BOX64_KDE_PROFILE_PLUGIN "Build the Dolphin/KIO Box64 profile properties plugin when KF5 or KF6 is available" OFF)
option(BUNDLE_X86_LIBS "Set to ON to download and install the x86 and x86_64 libraries bundle from the latest GitHub release during the install" OFF)
if(TERMUX)
set(TERMUX_PATH "/data/data/com.termux/files")
@@ -220,12 +223,12 @@ elseif(SD8G2)
elseif(SD8EG5)
add_definitions(-DSD8EG5)
# NOTE
# Even though Qualcomm Snapdragon 8 Elite Gen 5 relies on 3rd generation Oryon cores, it seems like the support for them
# Even though Qualcomm Snapdragon 8 Elite Gen 5 relies on 3rd generation Oryon cores, it seems like the support for them
# is not yet present in GCC and Clang, so for now we will use mostly the same optimization flags as SDORYON1, which houses
# 1st generation Oryon cores. This should still be fine since the main difference between the
# 1st generation Oryon cores. This should still be fine since the main difference between the
# two is the presence of SVE and SVE2, which are not yet used in Box64's ARM64 dynarec.
#
# As noted in the SDORYON1 section, GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument, however it seems like
# As noted in the SDORYON1 section, GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument, however it seems like
# Fedora does not like them very much, so this option should be taken with a grain of salt. It worked in my test case just fine.
set(CFLAGS -pipe -march=armv8.7-a+crypto+sm4+sha3+fp16+sve+sve2 -mtune=oryon-1)
elseif(SDORYON1)
@@ -262,8 +265,9 @@ elseif(LARCH64)
set(ASMFLAGS -pipe -march=loongarch64)
elseif(RV64)
add_definitions(-DRV64)
set(CFLAGS -pipe -march=rv64gc)
set(CFLAGS -pipe -march=rv64gc -fno-tree-vectorize)
set(ASMFLAGS -pipe -march=rv64gc)
add_compile_options(-fno-tree-vectorize)
elseif(PPC64LE)
add_definitions(-DPPC64LE)
set(CFLAGS -pipe -mcpu=power9)
@@ -471,6 +475,7 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/libtools/syscall_user_dispatch.c"
"${BOX64_ROOT}/src/libtools/decopcode.c"
"${BOX64_ROOT}/src/libtools/threads.c"
"${BOX64_ROOT}/src/steamwebhelper.c"
"${BOX64_ROOT}/src/tools/bitutils.c"
"${BOX64_ROOT}/src/tools/box64stack.c"
"${BOX64_ROOT}/src/tools/bridge.c"
@@ -607,7 +612,6 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedcuda.c"
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
"${BOX64_ROOT}/src/wrapped/wrappedcrypto.c"
"${BOX64_ROOT}/src/wrapped/wrappedcrypto3.c"
"${BOX64_ROOT}/src/wrapped/wrappedcurl.c"
@@ -698,6 +702,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibnuma.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibopus.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibomp.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
@@ -811,6 +816,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
"${BOX64_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
"${BOX64_ROOT}/src/wrapped/wrappedmimalloc.c"
"${BOX64_ROOT}/src/wrapped/wrappedudev0.c"
"${BOX64_ROOT}/src/wrapped/wrappedudev1.c"
"${BOX64_ROOT}/src/wrapped/wrappedunwind.c"
@@ -938,7 +944,6 @@ if(BOX32)
"${BOX64_ROOT}/src/wrapped32/wrappedlibpthread.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibrt.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibresolv.c"
"${BOX64_ROOT}/src/wrapped32/wrappedcrashhandler.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibgl.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibglu.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibglxnvidia.c"
@@ -1099,6 +1104,8 @@ if(RV64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_consts.c"
"${BOX64_ROOT}/src/dynarec/rv64/rv64_mov_imm.c"
"${BOX64_ROOT}/src/dynarec/rv64/updateflags_rv64.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
@@ -1110,6 +1117,7 @@ if(RV64_DYNAREC)
set(DYNAREC_PASS
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_helper.c"
"${BOX64_ROOT}/src/dynarec/rv64/updateflags_rv64_pass.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_tests.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_math.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_logic.c"
@@ -1142,6 +1150,12 @@ if(RV64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c"
@@ -1160,6 +1174,7 @@ if(LARCH64_DYNAREC)
${DYNAREC_SRC}
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_native.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"
@@ -1176,11 +1191,16 @@ if(LARCH64_DYNAREC)
set(DYNAREC_PASS
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_helper.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_native_pass.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_tests.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_math.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_shift.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_logic.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_0.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_1.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_2.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_3.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_0f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_660f.c"
@@ -1331,53 +1351,60 @@ add_library(mainobj OBJECT ${OS_LINUX_SRC} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPE
add_dependencies(mainobj generate_git_head_target)
add_dependencies(mainobj generate_dynacache_hashes)
add_executable(${BOX64})
target_link_libraries(${BOX64} mainobj)
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
add_dependencies(${BOX64} WRAPPERS)
if(BOX32)
add_dependencies(${BOX64} WRAPPERS32)
endif()
#add_dependencies(${BOX64} PRINTER)
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
if(STATICBUILD)
#set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-fuse-ld=gold -static -Wl,--no-relax -Wl,--allow-multiple-definition -ldl -lrt -lpthread -lresolv -lc -lutil -lm -Wl,-defsym,_DYNAMIC=0 -pthread")
target_link_libraries(${BOX64} c m dl pthread resolv util c)
else()
if(ANDROID)
if(TERMUX)
target_link_libraries(${BOX64} c m dl android-sysv-semaphore)
if(NOT NOBOX64)
add_executable(${BOX64})
target_link_libraries(${BOX64} mainobj)
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
add_dependencies(${BOX64} WRAPPERS)
if(BOX32)
add_dependencies(${BOX64} WRAPPERS32)
endif()
#add_dependencies(${BOX64} PRINTER)
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
if(STATICBUILD)
#set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-fuse-ld=gold -static -Wl,--no-relax -Wl,--allow-multiple-definition -ldl -lrt -lpthread -lresolv -lc -lutil -lm -Wl,-defsym,_DYNAMIC=0 -pthread")
target_link_libraries(${BOX64} c m dl pthread resolv util c)
else()
if(ANDROID)
if(TERMUX)
target_link_libraries(${BOX64} c m dl android-sysv-semaphore)
else()
target_link_libraries(${BOX64} c m dl)
endif()
else()
target_link_libraries(${BOX64} c m dl)
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
target_link_libraries(${BOX64} c m dl pthread resolv util c)
endif()
endif()
if(DYNAREC)
target_link_libraries(${BOX64} dynarec)
endif()
target_link_libraries(${BOX64} interpreter)
if(${CMAKE_VERSION} VERSION_LESS "3.13")
if(NOT NOLOADADDR)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS} ")
else()
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS} ")
endif()
endif()
else()
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
target_link_libraries(${BOX64} c m dl pthread resolv util c)
endif()
endif()
if(DYNAREC)
target_link_libraries(${BOX64} dynarec)
endif()
target_link_libraries(${BOX64} interpreter)
if(${CMAKE_VERSION} VERSION_LESS "3.13")
if(NOT NOLOADADDR)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS} ")
else()
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS} ")
endif()
endif()
else()
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
if(NOT NOLOADADDR)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
if(WITH_MOLD) # --image-base requires -no-pie in mold!
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -lm ")
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
if(NOT NOLOADADDR)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
# --image-base alone does not disable PIE with Clang/LLD.
# Android requires PIE.
if(NOT ANDROID)
target_link_options(${BOX64} PUBLIC -no-pie)
endif()
if(WITH_MOLD)
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-lm ")
endif()
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
else()
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
endif()
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
else()
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
endif()
endif()
endif()
@@ -1395,7 +1422,7 @@ if(_x86_64 OR _aarch64 OR _ppc64le)
add_definitions(-DCONFIG_64BIT)
endif()
if(NOT _x86 AND NOT _x86_64)
if(NOT _x86 AND NOT _x86_64 AND NOT NOBOX64)
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)
@@ -1597,14 +1624,28 @@ if(NOT _x86 AND NOT _x86_64)
endif()
endif()
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
if(NOT NOBOX64)
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
endif()
if(BUNDLE_X86_LIBS)
install(CODE "
message(STATUS \"Installing the x86 and x86_64 libraries bundle\")
execute_process(
COMMAND \"${BOX64_ROOT}/box64-bundle-x86-libs.sh\" --install
WORKING_DIRECTORY \"${BOX64_ROOT}\"
RESULT_VARIABLE BUNDLE_X86_LIBS_RESULT)
if(NOT BUNDLE_X86_LIBS_RESULT EQUAL 0)
message(FATAL_ERROR \"Failed to install the x86 and x86_64 libraries bundle\")
endif()")
endif()
string(REPLACE ";" "," DYNAREC_ASM_STR "${DYNAREC_ASM}")
@@ -1616,7 +1657,7 @@ if(WOW64 AND ARM_DYNAREC)
ExternalProject_Add(
wowbox64
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/wow64"
CMAKE_ARGS
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw.cmake
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
-DDYNAREC_ASM_STR=${DYNAREC_ASM_STR}
@@ -1629,55 +1670,76 @@ if(WOW64 AND ARM_DYNAREC)
add_dependencies(wowbox64 generate_git_head_target)
endif()
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_PACKAGE_DESCRIPTION "Box64 - Linux Userspace x86_64 Emulator with a twist")
if(NOT TERMUX)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
else()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore")
if(ARM64EC)
include(ExternalProject)
ExternalProject_Add(
box64ec
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/box64ec"
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw_arm64ec.cmake
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
-DINTERPRETER_STR=${INTERPRETER_STR}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
INSTALL_COMMAND ""
TEST_COMMAND ""
BUILD_ALWAYS ON
)
add_dependencies(box64ec generate_git_head_target)
endif()
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MAJOR\\s*")
string(REGEX REPLACE "BOX64_MAJOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_MAJOR ${TEMP_STRING})
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MINOR\\s*")
string(REGEX REPLACE "BOX64_MINOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_MINOR ${TEMP_STRING})
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_REVISION\\s*")
string(REGEX REPLACE "BOX64_REVISION" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_REVISION ${TEMP_STRING})
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX64_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${BOX64_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
if(NOT TERMUX)
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
endif()
if(_aarch64)
if(TERMUX)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "aarch64")
else()
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
endif()
elseif(_riscv64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
elseif(_ppc64le)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "ppc64el")
elseif(_x86_64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
else()
#probably wrong...
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
endif()
if(TERMUX)
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
endif()
if(NOT TERMUX)
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
else()
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
endif()
INCLUDE(CPack)
add_subdirectory(tests)
if(NOT NOBOX64)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_PACKAGE_DESCRIPTION "Box64 - Linux Userspace x86_64 Emulator with a twist")
if(NOT TERMUX)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
else()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore")
endif()
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MAJOR\\s*")
string(REGEX REPLACE "BOX64_MAJOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_MAJOR ${TEMP_STRING})
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MINOR\\s*")
string(REGEX REPLACE "BOX64_MINOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_MINOR ${TEMP_STRING})
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_REVISION\\s*")
string(REGEX REPLACE "BOX64_REVISION" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX64_REVISION ${TEMP_STRING})
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX64_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${BOX64_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
if(NOT TERMUX)
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
endif()
if(_aarch64)
if(TERMUX)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "aarch64")
else()
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
endif()
elseif(_riscv64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
elseif(_ppc64le)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "ppc64el")
elseif(_x86_64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
else()
#probably wrong...
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
endif()
if(TERMUX)
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
endif()
if(NOT TERMUX)
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
else()
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
endif()
INCLUDE(CPack)
endif()
if(NOT NOBOX64)
add_subdirectory(tests)
endif()
+2 -1
View File
@@ -28,4 +28,5 @@ Before submitting your PR:
# Coding guidelines
- Avoid adding third-party dependencies, extra files, extra headers, etc.
- Avoid adding third-party dependencies, extra files, extra headers, etc.
- New C source files must start with the license header `// SPDX-License-Identifier: MIT` or `# SPDX-License-Identifier: MIT` for Bash and Python scripts. Do not add headers to third-party files in `external/` or `src/include/`.
+4 -4
View File
@@ -55,17 +55,17 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
**Notes**
1. Box32 is still experimental.
1. Box32 is still experimental, but it's pretty stable now and can be used.
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
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 writing, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writing 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.
(or 0 to completely disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
---
@@ -109,7 +109,7 @@ So, in no particular order, I want to thank:
* For their major code contribution: rajdakin, mogery, ksco, xctan
* For their major financial contribution: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SpacemiT](https://www.spacemit.com/), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
And I also thank the many other people who participated even once in this project.
+1 -1
View File
@@ -102,7 +102,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
* 代码贡献:rajdakin, mogery, ksco, xctan
* 财务支持:[Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SpacemiT](https://www.spacemit.com/), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
我还要感谢很多人,即使他们只参与了一次本项目。
+1 -1
View File
@@ -109,7 +109,7 @@ Box64 використовує бібліотеки Vulkan, але зауваж
* За основний внесок у код: rajdakin, mogery, ksco, xctan
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
* За внесок у апаратне забезпечення: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* За внесок у апаратне забезпечення: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SpacemiT](https://www.spacemit.com/), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* За безперервну рекламу Box64: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/Команда [TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
+4
View File
@@ -1,5 +1,9 @@
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_amd64.deb,6fe41d04ea9ef8c5c684b14585caa7a4a7e04ad6805d59cdd29016960b737123
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_i386.deb,6d72a7ac94c0e3faa32f7dc07a1f4bc8a782d0ab39defca6e9322dd06afd638f
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_amd64.deb,a9a5e1f53b7e27a3f2b8388929bb622d3c6c35a4e42ac166697444e5ed662fd5
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_i386.deb,15f81212576c500e47e72ff05b1b705ef62640ef0a1b8e2c34d848c16ee30728
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
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/g/gcc-10/libgfortran5_10.2.1-6_amd64.deb 6fe41d04ea9ef8c5c684b14585caa7a4a7e04ad6805d59cdd29016960b737123
4 https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_i386.deb 6d72a7ac94c0e3faa32f7dc07a1f4bc8a782d0ab39defca6e9322dd06afd638f
5 https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_amd64.deb a9a5e1f53b7e27a3f2b8388929bb622d3c6c35a4e42ac166697444e5ed662fd5
6 https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_i386.deb 15f81212576c500e47e72ff05b1b705ef62640ef0a1b8e2c34d848c16ee30728
7 https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb 6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
8 https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb 4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
9 https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
+137 -15
View File
@@ -1,26 +1,143 @@
#!/bin/sh
# SPDX-License-Identifier: MIT
set -ex
set -e
trap cleanup_exit INT TERM EXIT
cleanup_exit()
{
echo "Running cleanup_exit..."
log "Running cleanup_exit..."
rm -rf /tmp/box64-bundle.*
}
# progress messages are only printed with --debug
log()
{
if [ -n "${verbose}" ]; then
echo "$@"
fi
}
usage()
{
cat << EOF
Usage: ${0} [OPTION]
Options:
--build Build the x86 library bundle archives from Linux distribution
packages.
--install Install the x86 library bundle from the latest GitHub release.
The bundle is only downloaded when at least one local file does
not match the checksums of the latest release. It is extracted
to the root of the file system or into DESTDIR when that
environment variable is set.
--debug Log every command that is run and every file that is extracted
or archived. Without it, --build is silent unless it fails. Can
be combined with --build or --install.
--help Show this help message.
EOF
}
# parse the arguments before anything else so that --debug logs everything
mode=""
verbose=""
quiet="q"
for arg in "$@"; do
case "${arg}" in
--build|--install)
mode="${arg}"
;;
--debug)
set -x
verbose="v"
quiet=""
;;
--help|-h)
usage
exit 0
;;
*)
echo "E: Unknown argument (${arg})"
usage
exit 1
;;
esac
done
if [ -z "${mode}" ]; then
echo "E: A --build or --install argument is required"
usage
exit 1
fi
repo_url="https://github.com/ptitSeb/box64"
# compare the local files to the latest release and, on any mismatch, install it
install_bundle()
{
# find the latest release
release=$(basename "$(${curl} -Ls -o /dev/null -w '%{url_effective}' "${repo_url}/releases/latest")")
case "${release}" in
v*) ;;
*)
echo "E: Unable to determine the latest release"
exit 1
;;
esac
bundle_url="${repo_url}/releases/download/${release}/box64-bundle-x86-libs-${release}"
bundle_checksums="${dir_tmp}/box64-bundle-x86-libs-${release}.sha256"
bundle_archive="${dir_tmp}/box64-bundle-x86-libs-${release}.tar.gz"
# the checksum paths are relative to the root of the destination
${curl_cmd} "${bundle_checksums}" "${bundle_url}.sha256"
if [ ! -d "${dir_dest}" ]; then
mkdir -p "${dir_dest}"
fi
cd "${dir_dest}"
if ${sha256sum} --check --quiet "${bundle_checksums}" \
> "${dir_tmp}/mismatches" 2> /dev/null; then
echo "I: The x86 library bundle ${release} is already installed in ${dir_dest}"
return 0
fi
# a single mismatch means the whole bundle is downloaded and extracted again
echo "I: $(wc -l < "${dir_tmp}/mismatches") file(s) do not match the latest bundle"
if [ ! -w "${dir_dest}" ]; then
echo "E: ${dir_dest} is not writable, run as root to install the x86 library bundle ${release}"
exit 1
fi
${curl_cmd} "${bundle_archive}" "${bundle_url}.tar.gz"
${tar} --extract --no-same-owner --file "${bundle_archive}" --directory "${dir_dest}"
# verify the installation
cd "${dir_dest}"
if ! ${sha256sum} --check --quiet "${bundle_checksums}"; then
echo "E: Invalid checksums after installing the x86 library bundle ${release}"
exit 1
fi
echo "I: Installed the x86 library bundle ${release} into ${dir_dest}"
}
# we must have few tools
awk=$(which awk) || { echo "E: You must have awk" && exit 1; }
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
curl=$(which curl) || { echo "E: You must have curl" && exit 1; }
curl_cmd="${curl} --connect-timeout 5 --retry 5 --retry-delay 1 --create-dirs -fsSLo"
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
sha256sum=$(which sha256sum) || { echo "E: You must have sha256sum" && exit 1; }
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
tar=$(which tar) || { echo "E: You must have tar" && exit 1; }
current_dir=$(pwd)
dir_tmp="$(mktemp -d /tmp/box64-bundle.XXXXXX)"
dir_dest="${DESTDIR:-/}"
if [ "${mode}" = "--install" ]; then
install_bundle
exit 0
fi
# we must have few more tools to build the bundle
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
# download the packages
while IFS= read -r line; do
@@ -41,7 +158,7 @@ while IFS= read -r line; do
done < box64-bundle-x86-libs.csv
# generate the bundle packages archive
tar -C "${dir_tmp}"/bundle-pkgs -czvf "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
tar -C "${dir_tmp}"/bundle-pkgs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
# extract the packages
cd "${dir_tmp}"/bundle-pkgs
@@ -54,21 +171,26 @@ for file in *.deb *.eopkg *.rpm *.xbps; do
cd "${dir_tmp}"/bundle-libs
case "${extension}" in
deb)
echo "I: DEB (Debian) package detected (${file})"
log "I: DEB (Debian) package detected (${file})"
ar x "${dir_tmp}"/bundle-pkgs/"${file}"
tar -xf data.tar*
;;
eopkg)
echo "I: EOPKG (Solus Linux) package detected (${file})"
${unzip} -o "${dir_tmp}"/bundle-pkgs/"${file}"
log "I: EOPKG (Solus Linux) package detected (${file})"
${unzip} -o"${quiet}" "${dir_tmp}"/bundle-pkgs/"${file}"
tar -xf install.tar.xz
;;
rpm)
echo "I: RPM (Fedora) detected (${file})"
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
log "I: RPM (Fedora) detected (${file})"
if [ -n "${verbose}" ]; then
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
else
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" \
| ${cpio} -idm --quiet 2> /dev/null
fi
;;
xbps)
echo "I: XBPS (Void Linux) package detected (${file})"
log "I: XBPS (Void Linux) package detected (${file})"
tar -xf "${dir_tmp}"/bundle-pkgs/"${file}"
;;
esac
@@ -95,7 +217,7 @@ set -- libc libpthread librt libGL libX11 libasound libdl libm libbsd libutil \
libxcb-xfixes libxcb-shape libxcb-shm libxcb-randr libxcb-image \
libxcb-keysyms libxcb-xtest libxcb-glx libxcb-dri2 libxcb-dri3 libXtst libXt \
libXcomposite libXdamage libXmu libxkbcommon libxkbcommon-x11 \
libpulse-simple libpulse libvulkan ld-linux-x86-64 crashhandler \
libpulse-simple libpulse libvulkan ld-linux-x86-64 \
libtcmalloc_minimal libanl ld-linux libthread_db
for file in "$@"; do
rm -f "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu/"${file}".so*
@@ -124,7 +246,7 @@ for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
cd "${dir_lib}"
for lib in lib*.so*; do
lib_base="$(echo "${lib}" | awk -F'.' '{print $1"."$2}')"
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null; then
if ! ls "${dir_lib}/${lib_base}" > /dev/null 2>&1; then
ln -s "${lib}" "${lib_base}"
fi
done
@@ -136,4 +258,4 @@ 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 .
tar -C "${dir_tmp}"/bundle-libs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-libs.tar.gz .
+1
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
from __future__ import annotations
import os
+1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
from __future__ import annotations
import argparse
+1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
from __future__ import annotations
import argparse
+2
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
from __future__ import annotations
from dataclasses import dataclass
@@ -102,6 +103,7 @@ PROFILE_SETTINGS = {
("BOX64_DYNAREC_BIGBLOCK", "0"),
("BOX64_DYNAREC_SAFEFLAGS", "2"),
("BOX64_DYNAREC_STRONGMEM", "2"),
("BOX64_DYNAREC_CALLRET", "3"),
),
"safe": (
("BOX64_DYNAREC_BIGBLOCK", "0"),
+1
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
from __future__ import annotations
import json
+195 -195
View File
@@ -1,178 +1,178 @@
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
* 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
-- 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.
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
=> Support for SteamRT3 & new Proton 11
=> New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
* This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
* => Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
* => Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
* => Support for SteamRT3 & new Proton 11
* => New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
box64 (0.4.0) unstable; urgency=low
This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
=> Improved compatibility accross all architecture, allowing more DRM protected game to run
=> the prefix refactor helped removed lots of redundant source file, simplifying maintenance
=> BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
* This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
* => Improved compatibility accross all architecture, allowing more DRM protected game to run
* => the prefix refactor helped removed lots of redundant source file, simplifying maintenance
* => BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
box64 (0.3.8) unstable; urgency=low
This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
* This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
=> DynaCache for faster loading of program, and avoid runtime hicups
=> Batter box32 compatibility (much less "Out of Memory" error)
=> Unity3D games on Wayland are working now
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
* => DynaCache for faster loading of program, and avoid runtime hicups
* => Batter box32 compatibility (much less "Out of Memory" error)
* => Unity3D games on Wayland are working now
* => Volatile Metadata fully supported and handled, making games like Starfield to just work.
* => More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
box64 (0.3.6) unstable; urgency=low
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
* This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
* => WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
* => it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
* => Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
* => The precision control bit of x87 is now handled, allowing some older games to run correctly
* => More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
box64 (0.3.4) unstable; urgency=low
* This version is Faster and more compatible
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
* => On ARM64, Box64 now support more DRM types than before.
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
* Please check CHAGELOG.md for more details
* This version is Faster and more compatible
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
* => On ARM64, Box64 now support more DRM types than before.
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
* Please check CHAGELOG.md for more details
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
box64 (0.3.2) unstable; urgency=low
* Introduced Box32 to run 32bits apps on 64bits OS
* => Box32 is a build option for Box64, and is disabled by default
* => Optionnal binfmt integration available for Box32
* => Wrapped some basics libs, including graphics and sounds so a few games already works
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
* => Available on the 3 Dynarec backend, with different implementations
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* +> Can lead to large speedup on certain cases
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
* Some bugfix and improvment in the Signal handler and internal memory tracking
* Improvment to TRAP signal generation and Handling
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
* Improved some x87 operations, like long double handling and infinity comparisons...
* Dynarec: ARM64 fixes to a few opcodes
* Dynarec: RV64 fixes to many opcodes
* Dynarec: LA64 fixes to a few opcodes
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
* ElfLoader: Improved object fetching
* New build profile for SD865 and ORYON
* Changed the installation folder of x86 libs to avoid conflict with linux distro
* Added a few syscalls
* Some more Vulkan extensions wrapped
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
* Introduced Box32 to run 32bits apps on 64bits OS
* => Box32 is a build option for Box64, and is disabled by default
* => Optionnal binfmt integration available for Box32
* => Wrapped some basics libs, including graphics and sounds so a few games already works
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
* => Available on the 3 Dynarec backend, with different implementations
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* +> Can lead to large speedup on certain cases
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
* Some bugfix and improvment in the Signal handler and internal memory tracking
* Improvment to TRAP signal generation and Handling
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
* Improved some x87 operations, like long double handling and infinity comparisons...
* Dynarec: ARM64 fixes to a few opcodes
* Dynarec: RV64 fixes to many opcodes
* Dynarec: LA64 fixes to a few opcodes
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
* ElfLoader: Improved object fetching
* New build profile for SD865 and ORYON
* Changed the installation folder of x86 libs to avoid conflict with linux distro
* Added a few syscalls
* Some more Vulkan extensions wrapped
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
box64 (0.3.0) unstable; urgency=low
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
* Dynarec: ARM64 some fixes to a few opcodes
* Dynarec: LA64 many new opcodes added, and fixes.
* Dynarec: RV64 some new opcodes added, many fixes.
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
* Dynarec: RV64 improved LOCK CMPXCHG handling
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
* ElfLoader: Added a new type of relocation
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
* Dynarec: ARM64 some fixes to a few opcodes
* Dynarec: LA64 many new opcodes added, and fixes.
* Dynarec: RV64 some new opcodes added, many fixes.
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
* Dynarec: RV64 improved LOCK CMPXCHG handling
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
* ElfLoader: Added a new type of relocation
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
box64 (0.2.8) unstable; urgency=low
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
* Reworked X11 Callback handling, for better stability
* Reworked exit and the load/unload of libs and symbol resolution
* Some more profiles in box64rc
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
* => should improve games stability
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
* Dynarec: RV64 lots of opcoded added.
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
* Dynarec: Better handling of large block in the dynarec
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
* Reworked X11 Callback handling, for better stability
* Reworked exit and the load/unload of libs and symbol resolution
* Some more profiles in box64rc
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
* => should improve games stability
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
* Dynarec: RV64 lots of opcoded added.
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
* Dynarec: Better handling of large block in the dynarec
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
box64 (0.2.6) unstable; urgency=low
* X64Libs: Updated libstdc++ & libgcc_s
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
* Dynarec: More opcodes on ARM64 & RV64
* Dynarec: Fixed some flags propagation issues inside blocks
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
* Dynarec: RV64: Many fixes, making Wow64 apps running
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
* CPU: Added full support for SSE4.2
* CPU: Added full support for SHA extension
* ElfLoader: rework how elf memory is handled
* Emulation: Added some more syscalls
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
* Wrapping: Removed faked libunwind wrapping
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
* OS: Added profile to build for Android and Termux.
* OS: New option to use mold for a high speed link
* => More hadware support, more functions wrapped for an improve compatibity
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
* => Some work also to reduce the memory footprint
* X64Libs: Updated libstdc++ & libgcc_s
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
* Dynarec: More opcodes on ARM64 & RV64
* Dynarec: Fixed some flags propagation issues inside blocks
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
* Dynarec: RV64: Many fixes, making Wow64 apps running
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
* CPU: Added full support for SSE4.2
* CPU: Added full support for SHA extension
* ElfLoader: rework how elf memory is handled
* Emulation: Added some more syscalls
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
* Wrapping: Removed faked libunwind wrapping
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
* OS: Added profile to build for Android and Termux.
* OS: New option to use mold for a high speed link
* => More hadware support, more functions wrapped for an improve compatibity
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
* => Some work also to reduce the memory footprint
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
box64 (0.2.4) unstable; urgency=low
@@ -199,74 +199,74 @@ box64 (0.2.4) unstable; urgency=low
* => Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
* => Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
box64 (0.2.2) unstable; urgency=low
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
* Improved memory protection tracking and signal handling, again
* Simplified mutex handling (faster, cleaner)
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
* Added d3dadaptor9 wrapping
* More wrapped libs (especially on the gtk familly)
* Improved/fixed some Syscall handling
* Refactored Strong Memory Model emulation (faster and more accurate)
* Added some more opcode to ARM64 Dynarec, and fixed some other
* Some fixes to flags handling in the Dynarec on some special cases
* Refactor library loading/unloading, with refcount.
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
* Improved mmap mapping, espcially with MAP_32BITS flag
* More wrapped functions and syscalls
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
* More support on the RV64 port
* More support to build under musl environment
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
* Improved memory protection tracking and signal handling, again
* Simplified mutex handling (faster, cleaner)
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
* Added d3dadaptor9 wrapping
* More wrapped libs (especially on the gtk familly)
* Improved/fixed some Syscall handling
* Refactored Strong Memory Model emulation (faster and more accurate)
* Added some more opcode to ARM64 Dynarec, and fixed some other
* Some fixes to flags handling in the Dynarec on some special cases
* Refactor library loading/unloading, with refcount.
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
* Improved mmap mapping, espcially with MAP_32BITS flag
* More wrapped functions and syscalls
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
* More support on the RV64 port
* More support to build under musl environment
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
box64 (0.2.0) unstable; urgency=low
* Wrapped more vulkan function, dxvk 2.0 now works
* Added support for overridden malloc/free functions
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
* Improved elf loader
* Improved dlsym handling with RTLD_NEXT
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
* Added BOX64_ROLLING_LOG to have details log only on crash
* Work on alignment for some of pthread structures
* More wrapped libraries in the gtk family
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
* Improved TLS Size handling (Unity3D games now works)
* More PageSize Compile options
* Improved execv family of function to have better box64 integration
* Added support for wrapped libfuse so AppImage works
* Adjusted the binfmt integration so AppImage are automaticaly picked
* Improved FAudio, SDL2, GL (and more) wrapping
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
* Improved Signal Handling and memory protection traking
* Some signature fixes to some wrapped functions (in libc)
* Added more syscalls
* Added a lot of new opcodes to the ARM64 Dynarec
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
* Fix typos and arch type string by @archanox in #321
* Fix grammar by @Jai-JAP in #326
* Enable 64k page size by @martinmanyhats in #334
* Align address when call mprotect by @wannacu in #336
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
* add 18.04 tegra X1 github actions by @theofficialgman in #345
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
* Add SW64 base support by @wannacu in #382
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
* Create X64WINE.md by @WheezyE in #423
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
* Malloc override by @ptitSeb in #437
* Remove dynablocklist by @ptitSeb in #438
* Fix Pkgbuilds by @Jai-JAP in #452
* Wrapped more vulkan function, dxvk 2.0 now works
* Added support for overridden malloc/free functions
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
* Improved elf loader
* Improved dlsym handling with RTLD_NEXT
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
* Added BOX64_ROLLING_LOG to have details log only on crash
* Work on alignment for some of pthread structures
* More wrapped libraries in the gtk family
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
* Improved TLS Size handling (Unity3D games now works)
* More PageSize Compile options
* Improved execv family of function to have better box64 integration
* Added support for wrapped libfuse so AppImage works
* Adjusted the binfmt integration so AppImage are automaticaly picked
* Improved FAudio, SDL2, GL (and more) wrapping
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
* Improved Signal Handling and memory protection traking
* Some signature fixes to some wrapped functions (in libc)
* Added more syscalls
* Added a lot of new opcodes to the ARM64 Dynarec
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
* Fix typos and arch type string by @archanox in #321
* Fix grammar by @Jai-JAP in #326
* Enable 64k page size by @martinmanyhats in #334
* Align address when call mprotect by @wannacu in #336
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
* add 18.04 tegra X1 github actions by @theofficialgman in #345
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
* Add SW64 base support by @wannacu in #382
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
* Create X64WINE.md by @WheezyE in #423
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
* Malloc override by @ptitSeb in #437
* Remove dynablocklist by @ptitSeb in #438
* Fix Pkgbuilds by @Jai-JAP in #452
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
+35 -5
View File
@@ -4,9 +4,39 @@ The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-b
## Usage
### User
Add `--debug` to any command to log every command that is run, along with every file that `tar`, `cpio`, and `unzip` handle. Without it, `--build` is silent unless it fails.
Install the bundle from the latest [GitHub release](https://github.com/ptitSeb/box64/releases/latest). This only requires `coreutils`, `curl`, and `tar`.
```
sudo ./box64-bundle-x86-libs.sh --install
```
The bundle can also be installed as part of a Box64 installation by turning on the `BUNDLE_X86_LIBS` option. It is off by default. From the `build` directory of a [compiled Box64](COMPILE.md):
```
cmake .. -D BUNDLE_X86_LIBS=ON
make -j4
sudo make install
```
Optionally set the environment variable `DESTDIR` to extract to a different location than `/`.
```
DESTDIR=/tmp/box64 ./box64-bundle-x86-libs.sh --install
```
```
make install DESTDIR=/tmp/box64
```
The checksums of the latest release are compared to the local files first. If every file matches, nothing is downloaded. If at least one file is missing or different, the whole bundle is downloaded, extracted, and then verified.
### Administrator
Install required dependencies for the bundle script.
Build the bundle from Linux distribution packages. Install the required dependencies for the bundle script.
- Arch Linux
```
@@ -23,11 +53,11 @@ Install required dependencies for the bundle script.
sudo dnf install binutils coreutils curl tar zstd
```
Run `box64-bundle-x86-libs.sh`. This will create two archives:
Run `box64-bundle-x86-libs.sh --build`. This will create two archives:
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
Extract the library archive. Box will automatically search these paths for library files to emulate.
Extract the library archive manually. Box will automatically search these paths for library files to emulate.
```
sudo tar --extract --no-same-owner --file box64-bundle-x86-libs.tar.gz --directory /
@@ -48,13 +78,13 @@ Preference of operating system packages that provide a library:
2. DEBs from Debian 11 provide 5 years of updates.
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
5. Other (whereever a library is packaged)
5. Other (wherever a library is packaged)
Some essential libraries will always be emulated and should be bundled. The full list can be found in the [in the core source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/core.c#L413).
Some essential library files will never be emulated (only natively wrapped instead) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/librarian/library.c#L440). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
For finding package names that contain a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
- DEB
- `apt-file <LIBRARY_FILE>`
- EOPKG
+3 -2
View File
@@ -32,8 +32,9 @@ If you also want binfmt integration on 32bits binaries, you also need to add `-D
### Note about WowBox64
A highly experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
An experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
It will build alongside the regular Box64, and produce a `wowbox64.dll` file in `build/wowbox64-prefix/src/wowbox64-build/` directory.
You can also add ̀`-DNOOX64=ON` to not build the main box64 binary to save compilation time if you plan to only use the wowbox64 dll.
### Note about binfmt_misc on Android
@@ -294,7 +295,7 @@ Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
#### Save memory at run time
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.
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, which may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
#### Build outside of a git repo
+8 -29
View File
@@ -80,14 +80,7 @@ Optimize CALL/RET opcodes. Available in WowBox64.
* 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. [Default]
### BOX64_DYNAREC_SEP
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
* 0: Do not add SEP at CALLRET return [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.
* 3: Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
### BOX64_DYNAREC_DF
@@ -312,13 +305,6 @@ Specify the CPU type to emulate. Available in WowBox64.
* 0: Emulate a Intel CPU Model. [Default]
* 1: Emulate a AMD CPU Model.
### BOX64_CRASHHANDLER
Use a dummy crash handler or not.
* 0: Use emulated crashhandler.so library if needed.
* 1: Use an internal dummy (empty) crashhandler.so library. [Default]
### BOX64_DYNAREC_BLEEDING_EDGE
Detect MonoBleedingEdge and apply conservative settings (Linux only).
@@ -419,6 +405,13 @@ Do not load any rc files.
* 0: Load rc files. [Default]
* 1: Do not load any rc files.
### BOX64_ONDEMAND_STEAMUI
Close the Steam UI while a game is running, and reopen it when the game is closed.
* 0: Disabled. [Default]
* 1: Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
### BOX64_PATH
Path to look for x86_64 binaries.
@@ -822,20 +815,6 @@ Add an environment variable.
## Fragile or Legacy
### BOX64_DYNAREC_PURGE
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.
### BOX64_DYNAREC_PURGE_AGE
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
* 4096: Default age threshold. [Default]
* XXXX: Custom age threshold (range: 10-65536).
### BOX64_DYNAREC_WAIT
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
+8 -29
View File
@@ -80,14 +80,7 @@ BOX64_DYNAREC_CALLRET=1
* 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,适用于所有类型的内存。
* 3: 在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。
### BOX64_DYNAREC_DF
@@ -245,20 +238,6 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
## 不稳定或遗留选项
### 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 中可用。
@@ -313,13 +292,6 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
* 0: 模拟某个 Intel CPU 型号。 [默认值]
* 1: 模拟某个 AMD CPU 型号。
### BOX64_CRASHHANDLER
是否使用模拟的 crashhandler.so 库。
* 0: 在需要时使用模拟的 crashhandler.so 库。
* 1: 使用内部定义的空 crashhandler.so 库。 [默认值]
### BOX64_DYNAREC_BLEEDING_EDGE
检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。
@@ -420,6 +392,13 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
* 0: 加载 rc 文件。 [默认值]
* 1: 不加载任何 rc 文件。
### BOX64_ONDEMAND_STEAMUI
在游戏运行时关闭 Steam UI,游戏结束后重新打开。
* 0: 禁用。 [默认值]
* 1: 在游戏运行时关闭 Steam UI,游戏结束后重新打开。
### BOX64_PATH
查找 x86_64 二进制文件的路径。
+10 -34
View File
@@ -118,14 +118,6 @@ Specify the CPU type to emulate. Available in WowBox64.
* 1 : Emulate a AMD CPU Model.
=item B<BOX64_CRASHHANDLER> =I<0|1>
Use a dummy crash handler or not.
* 0 : Use emulated crashhandler.so library if needed.
* 1 : Use an internal dummy (empty) crashhandler.so library. [Default]
=item B<BOX64_DLSYM_ERROR> =I<0|1>
Enable or disable the logging of dlsym errors.
@@ -176,22 +168,14 @@ Detect MonoBleedingEdge and apply conservative settings (Linux only).
* 1 : Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2>
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2|3>
Optimize CALL/RET opcodes. Available in WowBox64.
* 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. [Default]
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
* 0 : Do not add SEP at CALLRET return [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.
* 3 : Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
=item B<BOX64_DYNAREC_DF> =I<0|1>
@@ -345,22 +329,6 @@ Generate map file for Linux perf tool.
* 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).
* 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).
* 4096 : Default age threshold. [Default]
* XXXX : Custom age threshold (range: 10-65536).
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Available in WowBox64.
@@ -771,6 +739,14 @@ Do not load x64 Vulkan overlay.
* 1 : Do not load x64 Vulkan overlay.
=item B<BOX64_ONDEMAND_STEAMUI> =I<0|1>
Close the Steam UI while a game is running, and reopen it when the game is closed.
* 0 : Disabled. [Default]
* 1 : Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
=item B<BOX64_PATH> =I<XXXX>
Path to look for x86_64 binaries.
+1
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
# Usage: python gen.py
import json
+22 -79
View File
@@ -161,25 +161,6 @@
}
]
},
{
"name": "BOX64_CRASHHANDLER",
"description": "Use a dummy crash handler or not.",
"category": "Compatibility",
"wine": false,
"configurator": false,
"options": [
{
"key": "0",
"description": "Use emulated crashhandler.so library if needed.",
"default": false
},
{
"key": "1",
"description": "Use an internal dummy (empty) crashhandler.so library.",
"default": true
}
]
},
{
"name": "BOX64_DLSYM_ERROR",
"description": "Enable or disable the logging of dlsym errors.",
@@ -325,29 +306,10 @@
"key": "2",
"description": "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": true
}
]
},
{
"name": "BOX64_DYNAREC_SEP",
"description": "Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled",
"category": "Performance",
"wine": true,
"configurator": true,
"options": [
{
"key": "0",
"description": "Do not add SEP at CALLRET return",
"default": true
},
{
"key": "1",
"description": "Add SEP at CALLRET return, on memory that are from known binary files",
"default": false
},
{
"key": "2",
"description": "Add SEP at CALLRET return for all type of memory.",
"key": "3",
"description": "Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.",
"default": false
}
]
@@ -750,44 +712,6 @@
}
]
},
{
"name": "BOX64_DYNAREC_PURGE",
"description": "Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).",
"category": "Fragile or Legacy",
"wine": false,
"configurator": false,
"options": [
{
"key": "0",
"description": "DynaRec will not purge old unused DynaBlocks.",
"default": true
},
{
"key": "1",
"description": "DynaRec will purge old unused DynaBlocks based on tick age.",
"default": false
}
]
},
{
"name": "BOX64_DYNAREC_PURGE_AGE",
"description": "Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).",
"category": "Fragile or Legacy",
"wine": false,
"configurator": false,
"options": [
{
"key": "4096",
"description": "Default age threshold.",
"default": true
},
{
"key": "XXXX",
"description": "Custom age threshold (range: 10-65536).",
"default": false
}
]
},
{
"name": "BOX64_DYNAREC_SAFEFLAGS",
"description": "Behaviour of flags emulation on CALL/RET opcodes and other edge cases.",
@@ -1788,6 +1712,25 @@
}
]
},
{
"name": "BOX64_ONDEMAND_STEAMUI",
"description": "Close the Steam UI while a game is running, and reopen it when the game is closed.",
"category": "Compatibility",
"wine": false,
"configurator": true,
"options": [
{
"key": "0",
"description": "Disabled.",
"default": true
},
{
"key": "1",
"description": "Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.",
"default": false
}
]
},
{
"name": "BOX64_PATH",
"description": "Path to look for x86_64 binaries.",
@@ -2484,4 +2427,4 @@
}
]
}
]
]
+10 -31
View File
@@ -57,13 +57,6 @@
"1": "模拟某个 AMD CPU 型号。"
}
},
"BOX64_CRASHHANDLER": {
"description": "是否使用模拟的 crashhandler.so 库。",
"options": {
"0": "在需要时使用模拟的 crashhandler.so 库。",
"1": "使用内部定义的空 crashhandler.so 库。"
}
},
"BOX64_DLSYM_ERROR": {
"description": "启用或禁用 dlsym 错误的日志记录。",
"options": {
@@ -113,15 +106,8 @@
"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,适用于所有类型的内存。"
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。",
"3": "在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。"
}
},
"BOX64_DYNAREC_DF": {
@@ -258,20 +244,6 @@
"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": {
@@ -625,6 +597,13 @@
"1": "不加载 x64 Vulkan 覆盖层。"
}
},
"BOX64_ONDEMAND_STEAMUI": {
"description": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。",
"options": {
"0": "禁用。",
"1": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。"
}
},
"BOX64_PATH": {
"description": "查找 x86_64 二进制文件的路径。",
"options": {
@@ -873,4 +852,4 @@
"1": "不为 32 位二进制文件切换 personality。"
}
}
}
}
+4 -2
View File
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: MIT
#include "gdbjit.h"
#include <stdio.h>
#include <inttypes.h>
static char block_name_buffer[16];
static char block_name_buffer[2 * sizeof(uintptr_t) + 1];
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
{
@@ -9,7 +11,7 @@ static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb
struct gdb_object* object = cbs->object_open(cbs);
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
sprintf(block_name_buffer, "%x", block->x64start);
sprintf(block_name_buffer, "%" PRIxPTR, block->x64start);
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
+1
View File
@@ -1,4 +1,5 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
# create necessary directories
mkdir -p ~/steam/tmp # makes both ~/steam and ~/steam/tmp in one cmd
+7 -1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import os
import sys
@@ -416,8 +417,12 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
or match("libc", "tcmallocminimal") \
or match("libc", "tbbmallocproxy") \
or match("libc", "androidshmem") \
or match("libc", "mimalloc") \
or match("crypto", "libssl3") \
or match("tcmallocminimal", "tbbmallocproxy") \
or match("tcmallocminimal", "mimalloc") \
or match("tbbmallocproxy", "mimalloc") \
or match("libbsd", "mimalloc") \
or match("iconv", "libunistring2") \
or match("gomp", "libomp"):
continue
@@ -1094,7 +1099,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
"""
}
banner = "/********************************************************" + ('*'*len(ver)) + "***\n" \
banner = "// SPDX-License-Identifier: MIT\n" \
"/********************************************************" + ('*'*len(ver)) + "***\n" \
" * File automatically generated by rebuild_wrappers.py (v" + ver + ") *\n" \
" ********************************************************" + ('*'*len(ver)) + "***/\n"
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
+3 -1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import os
import sys
@@ -1405,7 +1406,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
#endif // __{filename}UNDEFS32_H_
"""
}
banner = "/***********************************************************" + ('*'*len(ver)) + "***\n" \
banner = "// SPDX-License-Identifier: MIT\n" \
"/***********************************************************" + ('*'*len(ver)) + "***\n" \
" * File automatically generated by rebuild_wrappers_32.py (v" + ver + ") *\n" \
" ***********************************************************" + ('*'*len(ver)) + "***/\n"
trim: Callable[[str], str] = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
+12 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <stdlib.h>
@@ -349,6 +350,8 @@ void FreeBox64Context(box64context_t** context)
ctx->atfork_sz = ctx->atfork_cap = 0;
}
box_free(ctx->quick_cleanups);
for(int i=0; i<MAX_SIGNAL; ++i)
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
signal(i, SIG_DFL);
@@ -437,6 +440,7 @@ void FreeBox64Context(box64context_t** context)
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
int idx = 0;
mutex_lock(&ctx->mutex_tls);
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
if(idx == ctx->elfsize) {
if(idx==ctx->elfcap) {
@@ -449,11 +453,13 @@ int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
} else {
ctx->elfs[idx] = head;
}
mutex_unlock(&ctx->mutex_tls);
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
return idx;
}
void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
mutex_lock(&ctx->mutex_tls);
if(GetTLSBase(head)) {
// should remove the tls info
int tlsbase = GetTLSBase(head);
@@ -465,19 +471,24 @@ void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
for(int i=0; i<ctx->elfsize; ++i)
if(ctx->elfs[i] == head) {
ctx->elfs[i] = NULL;
mutex_unlock(&ctx->mutex_tls);
return;
}
mutex_unlock(&ctx->mutex_tls);
}
int AddTLSPartition(box64context_t* context, int tlssize) {
mutex_lock(&context->mutex_tls);
int oldsize = context->tlssize;
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
context->tlssize += tlssize;
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
int ret = -context->tlssize; // negative offset
mutex_unlock(&context->mutex_tls);
// clean GS segment for current emu?
return -context->tlssize; // negative offset
return ret;
}
+2 -1
View File
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: MIT
#ifndef __BOX64_VERSION_H_
#define __BOX64_VERSION_H_
#define BOX64_MAJOR 0
#define BOX64_MINOR 4
#define BOX64_REVISION 4
#define BOX64_REVISION 5
#endif //__BOX64_VERSION_H_
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include "debug.h"
#include "box64version.h"
+4 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include "box64version.h"
#ifdef NOGIT
#define GITREV "nogit"
@@ -28,7 +29,9 @@ void PrintBox64Version(int prefix);
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
#ifdef _WIN32
#ifdef BOX64EC
#define BOX64_STR "Box64EC"
#elif defined(_WIN32)
#define BOX64_STR "WowBox64"
#else
#define BOX64_STR "Box64"
+22 -4
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,6 +12,7 @@
#include <sys/syscall.h>
#include <sys/mman.h>
#include <pthread.h>
#include <stdatomic.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <stdarg.h>
@@ -29,6 +31,7 @@
#include "debug.h"
#include "fileutils.h"
#include "box64context.h"
#include "steamwebhelper.h"
#include "box64cpu.h"
#include "box64cpu_util.h"
#include "wine_tools.h"
@@ -57,6 +60,7 @@ extern box64env_t box64env;
int box64_quit = 0;
int box64_exit_code = 0;
int box64_in_fatal_handler = 0;
int box64_stdout_no_w = 0;
uintptr_t box64_pagesize;
path_collection_t box64_addlibs = {0};
@@ -68,6 +72,7 @@ int box64_mapclean = 0;
int box64_zoom = 0;
int box64_steam = 0;
int box64_steamcmd = 0;
int box64_srt_logger = 0;
int box64_musl = 0;
int box64_nolibs = 0;
int box64_hasinterp = 0;
@@ -355,10 +360,10 @@ void KillAllInstances()
struct dirent* entry;
ssize_t len;
char proc_path[PATH_MAX];
char exe_path[PATH_MAX];
char exe_path[PATH_MAX+8];
char exe_target[PATH_MAX];
char self_name[PATH_MAX];
char self_name_with_deleted[PATH_MAX];
char self_name_with_deleted[PATH_MAX+16];
DIR* proc_dir = opendir("/proc");
if (proc_dir == NULL) {
@@ -726,6 +731,8 @@ void endBox64()
x64emu_t* emu = thread_get_emu();
void startTimedExit();
startTimedExit();
printf_log(LOG_DEBUG, "Calling thread_local destructors (exiting box64)\n");
CallThreadCleanup(emu);
// atexit first
printf_log(LOG_DEBUG, "Calling atexit registered functions (exiting box64)\n");
CallAllCleanup(emu);
@@ -738,14 +745,14 @@ void endBox64()
// unload needed libs
needed_libs_t* needed = my_context->elfs[0]->needed;
printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0);
int workers = get_active_emu_workers();
int workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed);
if (workers > 0) {
const int sleep_us = 10000; // 10ms
const int max_wait_ms = 2000; // 2s
int waited_ms = 0;
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) {
while ((workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed)) > 0 && waited_ms < max_wait_ms) {
usleep(sleep_us);
waited_ms += sleep_us / 1000;
}
@@ -1008,11 +1015,16 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
} else if(!strcmp(prog_, "steamcmd")) {
printf_log(LOG_INFO, "steamcmd detected\n");
box64_steamcmd = 1;
} else if(!strcmp(prog_, "srt-logger")) {
box64_srt_logger = 1;
} else if(!strcmp(prog_, "wineserver")) {
// check if this is wineserver
box64_wine = 1;
}
// Create a new context
#ifdef BOX32
box64_is32bits = FileIsX86ELF(prog);
#endif
my_context = NewBox64Context(argc - nextarg);
addLibPaths(my_context);
@@ -1178,6 +1190,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
printf_log(LOG_INFO, "Applied settings from rcfile\n");
displayMiscInfo();
}
if (BOX64ENV(ondemand_steamui) && (!strcmp(box64_guest_name, "steam") || !strcmp(box64_guest_name, "steamwebhelper")))
StartOnDemandSteamUI();
PrintEnvVariables(&box64env, LOG_INFO);
setupZydis(my_context);
@@ -1326,6 +1340,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
int script = my_context->bashpath?FileIsShell(my_context->fullpath):0;
int python3 = my_context->pythonpath?FileIsPython(my_context->fullpath):0;
printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively"));
#ifndef BOX32
if(!x86 && !my_context->box86path && FileIsX86ELF(my_context->fullpath))
printf_log(LOG_NONE, "Maybe you should enable BOX32 when building Box64 to enable 32bits program to be run\n");
#endif
fclose(f);
FreeCollection(&ld_preload);
int ret;
+438 -266
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <stdint.h>
+101 -60
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __ARM64_EMITTER_H__
#define __ARM64_EMITTER_H__
/*
@@ -229,25 +230,25 @@ int convert_bitmask(uint64_t bitmask);
#define LDURSBx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b10, imm9, Rn, Rt))
#define LDURSBxw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, (rex.w)?0b10:0b11, imm9, Rn, Rt))
#define LDxw(A, B, C) if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}
#define LDz(A, B, C) if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}
#define LDx(A, B, C) if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}
#define LDW(A, B, C) if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}
#define LDH(A, B, C) if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}
#define LDB(A, B, C) if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}
#define LDSW(A, B, C) if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}
#define LDSHxw(A, B, C) if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}
#define LDSHx(A, B, C) if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}
#define LDSHw(A, B, C) if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}
#define LDSBxw(A, B, C) if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}
#define LDSBx(A, B, C) if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}
#define LDSBw(A, B, C) if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}
#define STxw(A, B, C) if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}
#define STz(A, B, C) if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}
#define STx(A, B, C) if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}
#define STW(A, B, C) if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}
#define STH(A, B, C) if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}
#define STB(A, B, C) if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}
#define LDxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURxw(A, B, C);} else if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}} while(0)
#define LDz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURz(A, B, C);} else if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}} while(0)
#define LDx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURx(A, B, C);} else if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}} while(0)
#define LDW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURw(A, B, C);} else if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}} while(0)
#define LDH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURH(A, B, C);} else if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}} while(0)
#define LDB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURB(A, B, C);} else if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}} while(0)
#define LDSW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSW(A, B, C);} else if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}} while (0)
#define LDSHxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHxw(A, B, C);} else if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}} while (0)
#define LDSHx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHx(A, B, C);} else if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}} while (0)
#define LDSHw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHw(A, B, C);} else if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}} while (0)
#define LDSBxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBxw(A, B, C);} else if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}} while (0)
#define LDSBx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBx(A, B, C);} else if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}} while (0)
#define LDSBw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBw(A, B, C);} else if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}} while (0)
#define STxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURxw(A, B, C);} else if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}} while(0)
#define STz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURz(A, B, C);} else if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}} while(0)
#define STx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURx(A, B, C);} else if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}} while(0)
#define STW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURw(A, B, C);} else if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}} while(0)
#define STH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURH(A, B, C);} else if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}} while(0)
#define STB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURB(A, B, C);} else if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}} while(0)
// STR
#define STR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b00<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
@@ -463,9 +464,9 @@ int convert_bitmask(uint64_t bitmask);
#define CSINVx(Rd, Rn, Rm, cond) EMIT(CSINV_gen(1, Rm, cond, Rn, Rd))
#define CSINVw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(0, Rm, cond, Rn, Rd))
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w, Rm, cond, Rn, Rd))
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invertCond(cond))
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invertCond(cond))
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invertCond(cond))
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invCond(cond))
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invCond(cond))
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invCond(cond))
#define CSETMx(Rd, cond) CSINVx(Rd, xZR, xZR, invCond(cond))
#define CSETMw(Rd, cond) CSINVw(Rd, xZR, xZR, invCond(cond))
#define CSETMxw(Rd, cond) CSINVxw(Rd, xZR, xZR, invCond(cond))
@@ -479,9 +480,9 @@ int convert_bitmask(uint64_t bitmask);
#define CSNEGx(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(1, Rm, cond, Rn, Rd))
#define CSNEGw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(0, Rm, cond, Rn, Rd))
#define CSNEGxw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(rex.w, Rm, cond, Rn, Rd))
#define CNEGx(Rd, Rn, cond) CSNEGx(Rn, Rn, Rd, invCond(cond))
#define CNEGw(Rd, Rn, cond) CSNEGw(Rn, Rn, Rd, invCond(cond))
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rn, Rn, Rd, invCond(cond))
#define CNEGx(Rd, Rn, cond) CSNEGx(Rd, Rn, Rn, invCond(cond))
#define CNEGw(Rd, Rn, cond) CSNEGw(Rd, Rn, Rn, invCond(cond))
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rd, Rn, Rn, invCond(cond))
// AND / ORR
#define LOGIC_gen(sf, opc, N, immr, imms, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b100100<<23 | (N)<<22 | (immr)<<16 | (imms)<<10 | (Rn)<<5 | Rd)
@@ -648,9 +649,9 @@ int convert_bitmask(uint64_t bitmask);
#define ASRx(Rd, Rn, shift) SBFMx(Rd, Rn, shift, 63)
#define ASRw(Rd, Rn, shift) SBFMw(Rd, Rn, shift, 31)
#define ASRxw(Rd, Rn, shift) SBFMxw(Rd, Rn, shift, rex.w?63:31)
#define SBFIZx(Rd, Rn, lsb, width) SFBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
#define SBFIZw(Rd, Rn, lsb, width) SFBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
#define SBFIZxw(Rd, Rn, lsb, width) SFBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
#define SBFIZx(Rd, Rn, lsb, width) SBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
#define SBFIZw(Rd, Rn, lsb, width) SBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
#define SBFIZxw(Rd, Rn, lsb, width) SBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
// EXTR
#define EXTR_gen(sf, N, Rm, imms, Rn, Rd) ((sf)<<31 | 0b00<<29 | 0b100111<<23 | (N)<<22 | (Rm)<<16 | (imms)<<10 | (Rn)<<5 | (Rd))
@@ -827,26 +828,26 @@ int convert_bitmask(uint64_t bitmask);
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
#define VLD128(A, B, C) if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
#define VLD8(A, B, C) if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
#define VST8(A, B, C) if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}
#define VLD128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR128(A, B, C);} else if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}} while(0)
#define VLD64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR64(A, B, C);} else if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}} while(0)
#define VLD32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR32(A, B, C);} else if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}} while(0)
#define VLD16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR16(A, B, C);} else if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}} while(0)
#define VLD8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR8(A, B, C);} else if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}} while(0)
#define VST128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR128(A, B, C);} else if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}} while (0)
#define VST64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR64(A, B, C);} else if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}} while (0)
#define VST32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR32(A, B, C);} else if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}} while (0)
#define VST16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR16(A, B, C);} else if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}} while (0)
#define VST8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR8(A, B, C);} else if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}} while (0)
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VLDR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VSTR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VSTR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
#define VMEM_REG_gen(size, opc, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
@@ -902,7 +903,7 @@ int convert_bitmask(uint64_t bitmask);
#define VEORQ(Vd, Vn, Vm) EMIT(VLOGIC_gen(1, 0b00, Vm, Vn, Vd))
#define VEOR(Vd, Vn, Vm) EMIT(VLOGIC_gen(0, 0b00, Vm, Vn, Vd))
#define VLOGIC_immediate(Q, op, abc, cmade, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
#define VLOGIC_immediate(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
//#define V
#define SHL_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
@@ -962,7 +963,7 @@ int convert_bitmask(uint64_t bitmask);
#define VEXTQ_8(Rd, Rn, Rm, index) EMIT(EXT_vector(1, Rm, index, Rn, Rd))
// Shift Left and Insert (not touching lower part of dest)
#define SLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<1 | 1<<10 | (Rn)<<5 | (Rd))
#define VSLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
#define VSLIQ_8(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0001, (shift)&7, Vn, Vd))
#define VSLIQ_16(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
#define VSLIQ_32(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
@@ -972,14 +973,14 @@ int convert_bitmask(uint64_t bitmask);
#define VSLI_32(Vd, Vn, shift) EMIT(VSLI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
// Shift Right and Insert (not touching higher part of dest)
#define SRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<1 | 1<<10 | (Rn)<<5 | (Rd))
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (shift)&7, Vn, Vd))
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | (((shift)>>3)&7), (shift)&7, Vn, Vd))
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (shift)&7, Vn, Vd))
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
#define VSRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<11 | 1<<10 | (Rn)<<5 | (Rd))
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (8-(shift))&7, Vn, Vd))
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | ((64-(shift))>>3)&7, (64-(shift))&7, Vn, Vd))
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (8-(shift))&7, Vn, Vd))
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
// Reverse elements in 64-bit doublewords (vector). This instruction reverses the order of 8-bit, 16-bit, or 32-bit elements in each doubleword
#define VREVx_vector(Q, U, size, o0, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | (o0)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
@@ -1044,7 +1045,7 @@ int convert_bitmask(uint64_t bitmask);
// Double-precision to 64-bit
#define FMOVxD(Xd, Dn) EMIT(FMOV_general(1, 0b01, 0b00, 0b110, Dn, Xd))
// Top half of 128-bit to 64-bit
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, ob110, Vn, Xd))
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, 0b110, Vn, Xd))
#define FMOV_register(type, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b10000<<10 | (Rn)<<5 | (Rd))
#define FMOVS(Sd, Sn) EMIT(FMOV_register(0b00, Sn, Sd))
@@ -1251,7 +1252,7 @@ int convert_bitmask(uint64_t bitmask);
#define FCVTMUxwS(Xd, Sn) EMIT(FCVT_scalar(rex.w, 0b00, 0b10, 0b101, Sn, Xd))
#define FCVTMUwD(Wd, Dn) EMIT(FCVT_scalar(0, 0b01, 0b10, 0b101, Dn, Wd))
#define FCVTMUxD(Xd, Dn) EMIT(FCVT_scalar(1, 0b01, 0b10, 0b101, Dn, Xd))
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rfex.w, 0b01, 0b10, 0b101, Dn, Xd))
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rex.w, 0b01, 0b10, 0b101, Dn, Xd))
// Floating-point Convert to Signed integer, rounding to nearest with ties to even
#define FCVTNSwS(Wd, Sn) EMIT(FCVT_scalar(0, 0b00, 0b00, 0b000, Sn, Wd))
#define FCVTNSxS(Xd, Sn) EMIT(FCVT_scalar(1, 0b00, 0b00, 0b000, Sn, Xd))
@@ -2372,11 +2373,51 @@ int convert_bitmask(uint64_t bitmask);
// LRCPC extension
#define LDAPR_gen(sz, Rn, Rt) ((sz)<<30 | 0b111<<27 | 1<<23 | 1<<21 | 0b11111<<16 | 1<<15 | 0b100<<12 | (Rn)<<5 | (Rt))
#define LDAPRx(Rt, Rn) EMIT(LDAPR_gen(0b11, Rn, Rt))
#define LDAPRw(Rt, Rn) EMIT(LDAPR_gen(0b10, Rn, Rt))
#define LDAPRxw(Rt, Rn) EMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
#define LDAPRz(Rt, Rn) EMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
#define LDAPRH(Rt, Rn) EMIT(LDAPR_gen(0b01, Rn, Rt))
#define LDAPRB(Rt, Rn) EMIT(LDAPR_gen(0b00, Rn, Rt))
#define LDAPRx(Rt, Rn) LEMIT(LDAPR_gen(0b11, Rn, Rt))
#define LDAPRw(Rt, Rn) LEMIT(LDAPR_gen(0b10, Rn, Rt))
#define LDAPRxw(Rt, Rn) LEMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
#define LDAPRz(Rt, Rn) LEMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
#define LDAPRH(Rt, Rn) LEMIT(LDAPR_gen(0b01, Rn, Rt))
#define LDAPRB(Rt, Rn) LEMIT(LDAPR_gen(0b00, Rn, Rt))
// LRCPC2 extension
#define LRCPC2_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011001<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | (Rn)<<5 | (Rt))
#define STLURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b00, imm9, Rn, Rt))
#define STLURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b00, imm9, Rn, Rt))
#define STLURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b00, imm9, Rn, Rt))
#define STLURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b00, imm9, Rn, Rt))
#define STLURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b00, imm9, Rn, Rt))
#define STLURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b00, imm9, Rn, Rt))
#define LDAPURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b01, imm9, Rn, Rt))
#define LDAPURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b01, imm9, Rn, Rt))
#define LDAPURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b01, imm9, Rn, Rt))
#define LDAPURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b01, imm9, Rn, Rt))
#define LDAPURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b01, imm9, Rn, Rt))
#define LDAPURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b01, imm9, Rn, Rt))
#define LDAPURSW(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b10, imm9, Rn, Rt))
#define LDAPURSHw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b11, imm9, Rn, Rt))
#define LDAPURSHx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b10, imm9, Rn, Rt))
#define LDAPURSHxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, rex.w?0b10:0b11, imm9, Rn, Rt))
#define LDAPURSBw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b11, imm9, Rn, Rt))
#define LDAPURSBx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b10, imm9, Rn, Rt))
#define LDAPURSBxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, rex.w?0b10:0b11, imm9, Rn, Rt))
#define NOLRCPC() dyn->insts[ninst].use_lrcpc=0
// LRCPC3 extension
#define LRCPC3_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011101<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
#define VLDAPUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b11, imm9, Vn, Vt));} while(0)
#define VLDAPUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b01, imm9, Vn, Vt));} while(0)
#define VLDAPUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b01, imm9, Vn, Vt));} while(0)
#define VLDAPUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b01, imm9, Vn, Vt));} while(0)
#define VLDAPUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b01, imm9, Vn, Vt));} while(0)
#define VSTLUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b10, imm9, Vn, Vt));} while(0)
#define VSTLUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b00, imm9, Vn, Vt));} while(0)
#define VSTLUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b00, imm9, Vn, Vt));} while(0)
#define VSTLUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b00, imm9, Vn, Vt));} while(0)
#define VSTLUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b00, imm9, Vn, Vt));} while(0)
#endif //__ARM64_EMITTER_H__
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
//arm epilog for dynarec
//Save stuff, prepare stack and register
//called with pointer to emu as 1st parameter
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include "arm64_immenc.h"
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __ARM64_IMMENC_H__
#define __ARM64_IMMENC_H__
+24
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
//arm lock helper
//there is 2 part: read and write
// write return 0 on success, 1 on fail (value has been changed)
@@ -29,6 +30,7 @@
.global arm64_lock_decifnot0b
.global arm64_lock_storeb
.global arm64_lock_incif0
.global arm64_lock_inc
.global arm64_lock_decifnot0
.global arm64_lock_store
.global arm64_lock_store_dd
@@ -403,6 +405,28 @@ arm64_atomic_incif0:
mov w0, w1
ret
arm64_lock_inc:
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
tbnz w3, #0, arm64_atomic_inc
dmb ish
1:
ldaxr w1, [x0]
add w3, w1, #1
stlxr w2, w3, [x0]
cbnz w2, 1b
2:
mov w0, w1
ret
arm64_atomic_inc:
mov w1, #1
dmb ish
ldadd w1, w2, [x0]
mov w0, w2
ret
arm64_lock_store:
str w1, [x0]
dmb ish
+5 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __ARM64_LOCK__H__
#define __ARM64_LOCK__H__
#include <stdint.h>
@@ -76,8 +77,11 @@ extern void arm64_lock_storeb(void*p, uint8_t b);
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
extern int arm64_lock_incif0(void*p);
// increment atomically the int at [p]. Return the old value of [p]
extern int arm64_lock_inc(volatile void*p);
// decrement atomically the int at [p] (but only if p not 0)
extern int arm64_lock_decifnot0(void*p);
extern int arm64_lock_decifnot0(volatile void*p);
// atomic store (with memory barrier)
extern void arm64_lock_store(void*p, uint32_t v);
+40
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __ARM64_MAPPING_H__
#define __ARM64_MAPPING_H__
@@ -38,6 +39,32 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
*/
// x86 Register mapping
#ifdef BOX64EC
// x18 is the TEB and x6 is guest R9, the other scratch registers are x1 to x5
#define xRAX 10
#define xRCX 11
#define xRDX 12
#define xRBX 8
#define xRSP 20
#define xRBP 21
#define xRSI 16
#define xRDI 17
#define xR8 15
#define xR9 6
#define xR10 23
#define xR11 9
#define xR12 22
#define xR13 25
#define xR14 26
#define xR15 19
#define xFlags 7
#define xRIP 27
// convert a x86 register to native according to the register mapping
#define TO_NAT(A) (((uint8_t[]){10, 11, 12, 8, 20, 21, 16, 17, 15, 6, 23, 9, 22, 25, 26, 19})[(A)])
#define IS_GPR(A) (((uint8_t[]){0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, \
1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0})[(A)])
#else
#define xRAX 10
#define xRCX 11
#define xRDX 12
@@ -61,6 +88,9 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
// convert a x86 register to native according to the register mapping
#define TO_NAT(A) (xRAX + (A))
#define IS_GPR(A) ((A)>=xRAX && (A)<=xRIP)
#endif
// the Windows platform register, reloaded with the TEB after C calls
#define xTEB 18
// 32bits version
#define wEAX xRAX
@@ -86,8 +116,14 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
#define x3 3
#define x4 4
#define x5 5
#ifdef BOX64EC
#define x6 BOX64EC_x6_IS_GUEST_R9_USE_xR9
// x87pc is x5, a normal scratch: BOX64_DYNAREC_X87DOUBLE=2 precision tracking is not supported on Box64EC
#define x87pc 5
#else
#define x6 6
#define x87pc 7
#endif
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
// 32bits version of scratch
#define w1 x1
@@ -95,7 +131,11 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
#define w3 x3
#define w4 x4
#define w5 x5
#ifdef BOX64EC
#define w6 BOX64EC_w6_IS_GUEST_R9_USE_wR9
#else
#define w6 x6
#endif
#define w87pc x87pc
// emu is r0
#define xEmu 0
+5
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
//arm update linker table for dynarec
//called with pointer to emu as 1st parameter
@@ -14,6 +15,8 @@
arm64_next:
// emu is r0
// IP address is r1
str x14, [x0, #(8 * 4)] // RSP
str x27, [x0, #(8 * 17)] // RIP
sub sp, sp, (8 * 12)
stp x0, x1, [sp, (8 * 0)]
stp x10, x11, [sp, (8 * 2)]
@@ -47,6 +50,8 @@ arm64_next:
arm64_next_invalid:
// emu is r0
// IP address is r1
str x14, [x0, #(8 * 4)] // RSP
str x27, [x0, #(8 * 17)] // RIP
sub sp, sp, (8 * 12)
stp x0, x1, [sp, (8 * 0)]
stp x10, x11, [sp, (8 * 2)]
+71 -10
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include <stddef.h>
#include <string.h>
@@ -208,12 +209,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
}
if(isMask(opcode, "001110001x0iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "011110001x0iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "10111000100iiiiiiiii00nnnnnttttt", &a)) {
@@ -221,6 +222,37 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "LDURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "1x011001010iiiiiiiii00nnnnnttttt", &a)) {
int size = (opcode>>30)&3;
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "00011001010iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "01011001010iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "000110011x0iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "010110011x0iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "10011001100iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "LDAPURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "1x111000000iiiiiiiii00nnnnnttttt", &a)) {
int size = (opcode>>30)&3;
int offset = signExtend(imm, 9);
@@ -237,6 +269,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "STURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "1x011001000iiiiiiiii00nnnnnttttt", &a)) {
int size = (opcode>>30)&3;
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "STLUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "00011001000iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "STLURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "01011001000iiiiiiiii00nnnnnttttt", &a)) {
int offset = signExtend(imm, 9);
snprintf(buff, sizeof(buff), "STLURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) {
int size = (opcode>>30)&3;
int offset = (imm)<<size;
@@ -557,22 +605,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
}
if(isMask(opcode, "f1001011001mmmmmoooiiinnnnnddddd", &a)) {
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
snprintf(buff, sizeof(buff), "SUB %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
else if(shift==0)
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
else if(imm==0)
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
else
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
return buff;
}
if(isMask(opcode, "f0001011001mmmmmoooiiinnnnnddddd", &a)) {
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
snprintf(buff, sizeof(buff), "ADD %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
else if(shift==0)
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
else if(imm==0)
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
else
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
return buff;
}
// ---- LOGIC
@@ -1664,6 +1712,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
// LDAPUR/STLUR
if(isMask(opcode, "ff011101cL0iiiiiiiii10nnnnnttttt", &a)) {
const char* Y[] = {"B", "H", "S", "D", "Q"};
int sz = sf;
if(sz==0 && a.c)
sz = 4;
int offset = signExtend(imm, 9);
if(!offset)
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn]);
else
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
return buff;
}
// LDR/STR vector immediate
if(isMask(opcode, "ff111101cLiiiiiiiiiiiinnnnnttttt", &a)) {
const char* Y[] = {"B", "H", "S", "D", "Q"};
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef _ARM_PRINTER_H_
#define _ARM_PRINTER_H_
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
//arm prologue for dynarec
//Save stuff, prepare stack and register
//called with pointer to emu as 1st parameter
+106 -41
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -36,6 +37,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
int32_t i32, tmp;
int64_t i64, j64;
uint8_t u8;
uint8_t f_save;
uint8_t gb1, gb2, eb1, eb2;
uint16_t u16;
uint32_t u32;
@@ -983,8 +985,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
B_NEXT_nocond;
MARK;
STORE_XEMU_CALL(xRIP);
f_save = dyn->f;
CALL_S(const_native_br, -1);
LOAD_XEMU_CALL(xRIP);
dyn->f = f_save;
} else {
INST_NAME("Illegal 62");
if(BOX64DRENV(dynarec_safeflags)>1) {
@@ -1010,10 +1014,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEW(x1, 0);
GETGW(x2);
// Extract RPL (low 2 bits)
UBFXw(x6, ed, 0, 2);
UBFXw(x5, ed, 0, 2);
UBFXw(x4, gd, 0, 2);
// need_update = (dst_rpl < src_rpl)
CMPSw_REG(x6, x4);
CMPSw_REG(x5, x4);
CSETw(x5, cLT);
// ZF = need_update
BFIw(xFlags, x5, F_ZF, 1);
@@ -1054,6 +1058,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
TABLE64(x3, addr-4);
LDRSW_U12(x1, x3, 0);
PUSH1z(x1);
SMWRITE();
} else {
if (!i64) {
PUSH1z(xZR);
@@ -1213,7 +1218,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x6E:
case 0x6F:
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSD");
INST_NAME(opcode == 0x6E ? "OUTSB" : "OUTSD");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
@@ -1467,7 +1472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop=F8;
GETEB(x1, 0);
GETGB(x2);
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
emit_test8(dyn, ninst, x1, x2, x3, x4);
break;
case 0x85:
INST_NAME("TEST Ed, Gd");
@@ -1475,7 +1480,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop=F8;
GETGD;
GETED(0);
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x6);
emit_test32(dyn, ninst, rex, ed, gd, x3, x5);
break;
case 0x86:
INST_NAME("(LOCK)XCHG Eb, Gb");
@@ -1602,6 +1607,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else { // mem <= reg
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
NOLRCPC();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 0);
if(gd==wback) {
MOVx_REG(x2, wback);
@@ -1614,9 +1620,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// gd restored after that
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << (2 + rex.w), (1 << (2 + rex.w)) - 1, rex, &lock, 0, 0);
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
DMB_ISH();
lock = 1;
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
dyn->insts[ninst].use_lrcpc = 1;
else {
DMB_ISH();
lock = 1;
}
}
STxw(gd, ed, fixedaddress);
}
@@ -1665,8 +1675,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
lock = 1;
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
dyn->insts[ninst].use_lrcpc = 1;
else
lock = 1;
}
SMREADLOCK(lock);
LDxw(gd, ed, fixedaddress);
@@ -1834,6 +1847,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x9B:
INST_NAME("FWAIT");
if(BOX64ENV(dynarec_div0)) {
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
LDRH_U12(x2, xEmu, offsetof(x64emu_t, cw));
MVNw_REG(x2, x2); // ~CW
ANDw_REG(x1, x1, x2); // SW & ~CW
MOV32w(x3, 0x3F); // 6 exception flag bits
ANDw_REG(x1, x1, x3); // & 0x3F
CBZw_MARK3(x1); // no pending unmasked exception
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
MARK3;
}
break;
case 0x9C:
INST_NAME("PUSHF");
@@ -2006,6 +2035,7 @@ 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);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -2067,8 +2097,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 1);
LDRB_U12(x1, xRSI, 0);
STRB_U12(x1, xRDI, 0);
unscaled = 0;
LDB(x1, xRSI, 0);
STB(x1, xRDI, 0);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
@@ -2079,6 +2110,7 @@ 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);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -2103,8 +2135,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, rex.w?8:4);
LDRxw_U12(x1, xRSI, 0);
STRxw_U12(x1, xRDI, 0);
unscaled = 0;
LDxw(x1, xRSI, 0);
STxw(x1, xRDI, 0);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
@@ -2122,6 +2155,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -2144,6 +2178,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("CMPSB");
@@ -2154,8 +2189,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETDIR(x3, 1);
SMREAD();
LDRB_U12(x1, xRSI, 0);
LDRB_U12(x2, xRDI, 0);
unscaled = 0;
LDB(x1, xRSI, 0);
LDB(x2, xRDI, 0);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
@@ -2174,6 +2210,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -2196,6 +2233,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("CMPSD");
@@ -2206,8 +2244,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETDIR(x3, rex.w?8:4);
SMREAD();
LDRxw_U12(x1, xRSI, 0);
LDRxw_U12(x2, xRDI, 0);
unscaled = 0;
LDxw(x1, xRSI, 0);
LDxw(x2, xRDI, 0);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
@@ -2219,19 +2258,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
UXTBx(x1, xRAX);
u8 = F8;
MOV32w(x2, u8);
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
emit_test8c(dyn, ninst, x1, u8, x3, x4);
break;
case 0xA9:
INST_NAME("TEST EAX, Id");
SETFLAGS(X_ALL, SF_SET_PENDING);
i64 = F32S;
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4);
break;
case 0xAA:
if(rex.rep) {
INST_NAME("REP STOSB");
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
@@ -2283,7 +2322,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 1);
STRB_U12(xRAX, xRDI, 0);
unscaled = 0;
STB(xRAX, xRDI, 0);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
@@ -2292,6 +2332,7 @@ 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);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
@@ -2313,7 +2354,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, rex.w?8:4);
STRxw_U12(xRAX, xRDI, 0);
unscaled = 0;
STxw(xRAX, xRDI, 0);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
@@ -2324,6 +2366,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
INST_NAME("LODSB");
}
NOLRCPC();
GETDIR(x1, 1);
SMREAD();
if(rex.rep) {
@@ -2347,6 +2390,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
INST_NAME("LODSD");
}
NOLRCPC();
GETDIR(x1, rex.w?8:4);
if(rex.rep) {
CBZx_NEXT(xRCX);
@@ -2363,6 +2407,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xAE:
NOLRCPC();
switch(rex.rep) {
case 1:
case 2:
@@ -2394,6 +2439,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("SCASB");
@@ -2410,6 +2456,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xAF:
NOLRCPC();
switch(rex.rep) {
case 1:
case 2:
@@ -2440,6 +2487,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("SCASD");
@@ -2874,6 +2922,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else { // mem <= i32
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
NOLRCPC();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 4);
i64 = F32S;
if(i64) {
@@ -2937,6 +2986,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_PEND);
BARRIER(BARRIER_FLOAT);
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
TBZ_MARK(x3, 0);
TBZ_MARK(x3, 1); //GP if CS is incorect
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
if(u16<0x1000)
ADDz_U12(xRSP, xRSP, u16);
@@ -2945,6 +2996,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ADDz_REG(xRSP, xRSP, x1);
}
ret_to_next(dyn, ip, ninst, rex);
MARK;
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
MOV64x(xRIP, ip); // move back RIP to the opcode
CALL_S(const_native_priv, -1);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
break;
@@ -2953,8 +3009,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_PEND);
BARRIER(BARRIER_FLOAT);
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
TBZ_MARK(x3, 0);
TBZ_MARK(x3, 1); //GP if CS is incorect
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
ret_to_next(dyn, ip, ninst, rex);
MARK;
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
MOV64x(xRIP, ip); // move back RIP to the opcode
CALL_S(const_native_priv, -1);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
break;
@@ -3011,20 +3074,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
INST_NAME("INT 3");
if(!BOX64ENV(ignoreint3)) {
// check if TRAP signal is handled
TABLE64C(x1, const_context);
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
LDRx_REG(x3, x1, x2);
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
CMPSx_U12(x3, 0);
// commit df before branch, CALL_S in int3 path has FORCE_DFNONE
CHECK_DFNONE(0);
B_MARK(cEQ);
GETIP(addr); // update RIP
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_int3, -1);
LOAD_XEMU_CALL(xRIP);
MARK;
jump_to_epilog(dyn, addr, 0, ninst);
*need_epilog = 0;
*ok = 0;
@@ -3529,7 +3583,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETED(0);
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x3);
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4);
WBACK;
break;
case 3:
@@ -3548,7 +3602,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETED(0);
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x3);
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4);
WBACK;
break;
case 4:
@@ -3930,6 +3984,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOV64x(x4, j64);
}
LDRx_U12(x4, x4, 0);
if (BOX64DRENV(dynarec_callret) >= 3)
doLeaveBlock(dyn, ninst, x1, x2, x3);
BR(x4);
}
CLEARIP();
@@ -4068,8 +4124,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEB(x1, 1);
u8 = F8;
MOV32w(x2, u8);
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
emit_test8c(dyn, ninst, x1, u8, x3, x4);
break;
case 2:
INST_NAME("NOT Eb");
@@ -4234,7 +4289,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEDH(x1, 4);
i64 = F32S;
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4);
break;
case 2:
INST_NAME("NOT Ed");
@@ -4517,8 +4572,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SET_DFNONE();
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
break;
case 0xFA: /* STI */
case 0xFB: /* CLI */
case 0xFA: /* CLI */
case 0xFB: /* STI */
INST_NAME(opcode==0xFA?"CLI":"STI");
if(rex.is32bits && BOX64ENV(ignoreint3))
{} else {
@@ -4628,6 +4683,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LDRx_U12(x4, x4, 0);
if (BOX64DRENV(dynarec_callret) >= 3)
doLeaveBlock(dyn, ninst, x1, x2, x3);
BR(x4);
}
CLEARIP();
@@ -4644,6 +4701,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDxw(x1, wback, 0);
ed = x1;
LDH(x3, wback, rex.w?8:4);
TBZ(x3, 0, 4+4);
TBNZ_MARK2(x3, 1);
// Bad CS => GP
CALL_S(const_native_priv, -1);
jump_to_epilog(dyn, 0, xRIP, ninst);
MARK2;
LDH(x5, xEmu, offsetof(x64emu_t, segs[_CS]));
if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
BARRIER(BARRIER_FULL);
@@ -4673,7 +4736,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STPx_S7_preindex(x4, xRIP, xSP, -16);
}
if (rex.w) PUSH2(x5, xRIP); else PUSH2_32(x5, xRIP);
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
CALLRET_RET(can_continue);
if (BOX64DRENV(dynarec_callret) && !can_continue) {
@@ -4683,6 +4746,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LDRx_U12(x4, x4, 0);
if (BOX64DRENV(dynarec_callret) >= 3)
doLeaveBlock(dyn, ninst, x1, x2, x3);
BR(x4);
}
CLEARIP();
@@ -4709,7 +4774,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDxw(x1, wback, 0);
ed = x1;
LDH(x3, wback, rex.w?8:4);
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
jump_to_next(dyn, 0, ed, ninst, rex.w?0:1);
*need_epilog = 0;
*ok = 0;
+53 -21
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -160,6 +161,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x05:
INST_NAME("SYSCALL");
if (rex.is32bits) {
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
BARRIER(BARRIER_FLOAT);
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(const_native_ud, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
break;
}
NOTEST(x1);
SMEND();
GETIP(addr);
@@ -281,6 +298,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
NOLRCPC();
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(wback!=x1) {
MOVx_REG(x1, wback);
@@ -359,8 +377,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVHPS Ex, Gx");
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
VMOVeD(v1, 0, v0, 1);
INST_NAME("Illegal 0F 17");
UDF(0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VST1_64(v0, 1, ed);
@@ -485,6 +503,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
UDF(0);
} else {
INST_NAME("MOVNTPS Ex,Gx");
NOLRCPC();
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
@@ -1596,7 +1615,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
default:
*ok = 0;
DEFAULT;
}
break;
@@ -2534,8 +2552,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEB(x2, 0);
gd = x2; ed = x1; // swap gd/ed
emit_add8(dyn, ninst, x1, x2, x4, x5);
GBBACK; // gb gets x2 (old ed)
EBBACK; // eb gets x1 (sum)
EBBACK; // Eb writeback must be done first, as Gb writeback can clobber the address register
if (!(MODREG && wback == gb1 && wb2 == gb2))
GBBACK;
break;
case 0xC1:
INST_NAME("XADD Ed, Gd");
@@ -2577,6 +2596,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xC3:
INST_NAME("MOVNTI Ed, Gd");
NOLRCPC();
nextop=F8;
GETGD;
if(MODREG) { // reg <= reg
@@ -2666,32 +2686,43 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xC7:
// rep has no impact here
nextop = F8;
if(MODREG) switch((nextop>>3)&7) {
case 6:
INST_NAME("RDRAND Ed");
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
GETED(0);
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if(cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
if(rex.rep==2 || !rex.rep) {
if(rex.rep==2)
INST_NAME("RDSEED Ed");
else
INST_NAME("RDRAND Ed");
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
GETED(0);
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if(cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
} else {
CALL(rex.w?const_random64:const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
MOVxw_REG(ed, x1);
} else {
CALL(rex.w?const_random64:const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
DEFAULT;
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
MOVxw_REG(ed, x1);
break;
case 7:
INST_NAME("RDPID Ed");
SETFLAGS(X_CF, SF_SUBSET);
GETED(0);
CALL_(const_helper_getcpu, ed, x2);
IFX(X_CF) {
MOV32w(x2, 1);
BFIw(xFlags, x2, F_CF, 1);
}
break;
default:
DEFAULT;
@@ -2961,6 +2992,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE7:
INST_NAME("MOVNTQ Em, Gm");
NOLRCPC();
nextop = F8;
gd = (nextop&0x38)>>3;
if(MODREG) {
+17 -7
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -604,7 +605,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETEW(x1, 0);
GETGW(x2);
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
emit_test16(dyn, ninst, x1, x2, x3, x4);
break;
case 0x87:
@@ -883,6 +884,7 @@ 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);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -907,8 +909,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 2);
LDRH_U12(x1, xRSI, 0);
STRH_U12(x1, xRDI, 0);
unscaled = 0;
LDH(x1, xRSI, 0);
STH(x1, xRDI, 0);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
@@ -927,6 +930,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
@@ -949,6 +953,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("CMPSW");
@@ -972,13 +977,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
u16 = F16;
UBFXx(x1, xRAX, 0, 16);
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
emit_test16c(dyn, ninst, x1, u16, x3, x4);
break;
case 0xAB:
if(rex.rep) {
INST_NAME("REP STOSW");
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
@@ -1000,7 +1006,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 2);
STRH_U12(xRAX, xRDI, 0);
unscaled = 0;
STH(xRAX, xRDI, 0);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
@@ -1049,6 +1056,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
CBZx_NEXT(xRCX);
NOLRCPC();
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
@@ -1069,6 +1077,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK2(xRCX);
MARK3; // end
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
STOP_NATIVE_FLAGS(dyn, ninst);
break;
default:
INST_NAME("SCASW");
@@ -1122,7 +1131,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
INST_NAME("ROR Ew, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
if (u8) {
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETEW(x1, 1);
u8 = (F8)&0x1f;
@@ -1555,7 +1565,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1, 2);
u16 = F16;
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
emit_test16c(dyn, ninst, x1, u16, x3, x4);
break;
case 2:
INST_NAME("NOT Ew");
+121 -32
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -950,9 +951,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
}
} else {
MRS_nzcv(x3);
BFIx(x3, xFlags, 29, 1); // set C
MSR_nzcv(x3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(xFlags, 63, 0b0010);
else {
MRS_nzcv(x3);
BFIx(x3, xFlags, 29, 1); // set C
MSR_nzcv(x3); // load CC into ARM CF
}
}
IFX(X_CF) {
ADCSxw_REG(gd, gd, ed);
@@ -1276,12 +1281,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
PMULL2_128(q0, q0, q1);
break;
case 0b00000001:
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
PMULL_128(q0, q0, q1);
d0 = fpu_get_scratch(dyn, ninst);
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
PMULL_128(q0, d0, q1);
break;
case 0b00010000:
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
PMULL2_128(q0, q0, q1);
d0 = fpu_get_scratch(dyn, ninst);
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
PMULL2_128(q0, d0, q1);
break;
}
} else {
@@ -1317,6 +1324,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
ed = (nextop&7)+(rex.b<<3);
if(ed>7)
sse_reflect_reg(dyn, ninst, ed);
else
sse_mark_used(dyn, ninst, ed);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
@@ -1327,7 +1336,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MOVx_REG(x2, xRDX);
MOVx_REG(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
CALL(const_sse42_compare_string_explicit_len, x1);
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
if(u8&0b1000000) {
@@ -1405,6 +1414,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVBto(x2, d0, 0);
BFIw(x1, x2, 8, 8); // insert
}
#ifdef BOX64EC
int lreg = x2; // no x6 (guest R9): lreg is lost in min(lmem, lreg) and recomputed for SF
#else
int lreg = x6;
#endif
// get abs of eax / edx and find min
ADDSxw_U12(x2, xRAX, 0);
Bcond(cPL, 4+4);
@@ -1413,17 +1427,24 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
Bcond(cPL, 4+4);
NEGxw_REG(x3, x3);
MOV32w(x4, (u8&1)?8:16);
CMPSw_REG(x3, x4);
CSELw(x3, x3, x4, cLT); // x3 is lmem
CMPSw_REG(x2, x4);
CSELw(x6, x2, x4, cLT); // x6 is lreg
CMPSw_REG(x6, x3);
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
if(rex.w) {
CMPSx_REG(x3, x4);
CSELx(x3, x3, x4, cLO); // x3 is lmem
CMPSx_REG(x2, x4);
CSELx(lreg, x2, x4, cLO);
} else {
CMPSw_REG(x3, x4);
CSELw(x3, x3, x4, cLO); // x3 is lmem
CMPSw_REG(x2, x4);
CSELw(lreg, x2, x4, cLO);
}
CMPSw_REG(lreg, x3);
CSELw(x5, x3, lreg, cLT); // x5 is max(lmem, lreg)
CSELw(x2, lreg, x3, cLT); // x2 is min(lmem, lreg)
// x2 is min length 0-n_packed
MVNw_REG(x4, xZR);
LSLw_REG(x87pc, x4, x2);
BICw_REG(x1, x1, x87pc);
LSLw_REG(x2, x4, x2);
BICw_REG(x1, x1, x2);
LSLw_REG(x4, x4, x5);
ORRw_REG(x1, x1, x4);
ANDw_mask(x1, x1, 0, (u8&1)?7:15);
@@ -1455,8 +1476,17 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIw(xFlags, x5, F_ZF, 1);
}
IFX(X_SF) {
#ifdef BOX64EC
// lreg was overwritten by min(lmem, lreg), recompute it from abs(RAX)
ADDSxw_U12(x2, xRAX, 0);
Bcond(cPL, 4+4);
NEGxw_REG(x2, x2);
CMPSxw_REG(x2, x4);
CSETw(x5, cLO);
#else
CMPSw_REG(x6, x4);
CSETw(x5, cLT);
#endif
BFIw(xFlags, x5, F_SF, 1);
}
}
@@ -1481,11 +1511,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_DF);
if(gd>7) // no need to reflect cache as xmm0-xmm7 will be saved before the function call anyway
sse_reflect_reg(dyn, ninst, gd);
else
sse_mark_used(dyn, ninst, gd);
ADDx_U12(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
if(ed>7)
sse_reflect_reg(dyn, ninst, ed);
else
sse_mark_used(dyn, ninst, ed);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
@@ -1493,10 +1527,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MOVx_REG(x1, ed);
}
}
MOVw_REG(x2, xRDX);
MOVw_REG(x4, xRAX);
MOVx_REG(x2, xRDX);
MOVx_REG(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
CALL(const_sse42_compare_string_explicit_len, x1);
}
if(u8&0b1000000) {
@@ -1524,6 +1558,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
ed = (nextop&7)+(rex.b<<3);
if(ed>7)
sse_reflect_reg(dyn, ninst, ed);
else
sse_mark_used(dyn, ninst, ed);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
@@ -1573,11 +1609,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETG;
if(gd>7)
sse_reflect_reg(dyn, ninst, gd);
else
sse_mark_used(dyn, ninst, gd);
ADDx_U12(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
if(ed>7)
sse_reflect_reg(dyn, ninst, ed);
else
sse_mark_used(dyn, ninst, ed);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
@@ -1597,7 +1637,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MOV32w(x2, 31);
SUBw_REG(xRCX, x2, xRCX);
} else {
RBITxw(xRCX, x1);
RBITw(xRCX, x1);
CLZw(xRCX, xRCX);
}
break;
@@ -2450,7 +2490,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
SBFXx(x1, gd, 4, 12); // r1 = (gw>>4)
ADDx_REG_LSL(x3, wback, x1, 1); //(&ed)+=r1*2;
LDH(x1, x3, fixedaddress);
@@ -2494,7 +2534,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
UFLAG_IF {
CBZw_NEXT(x4);
}
#ifdef BOX64EC
// x1 to x5 are all in use and x6 is guest R9, so the address in x3 goes through the emu
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
emit_shld16(dyn, ninst, ed, gd, x4, x5, x3);
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
#else
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6);
#endif
EWBACK;
break;
@@ -2511,7 +2558,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
LDH(x4, x3, fixedaddress);
@@ -2564,7 +2611,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
CBZw_NEXT(x4);
} else {
}
#ifdef BOX64EC
// as SHLD, the address in x3 goes through the emu
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x3);
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
#else
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
#endif
EWBACK;
break;
case 0xAE:
@@ -2637,7 +2691,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
wback = 0;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
LDH(x4, x3, fixedaddress);
@@ -2706,10 +2760,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
SETFLAGS(X_CF, SF_SUBSET);
}
gd = x2;
GETEW(x1, 1);
u8 = F8;
u8&=rex.w?0x3f:0x0f;
u8&=0x0f;
IFX(X_CF) {
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
}
@@ -2723,7 +2776,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
GETEW(x1, 1);
u8 = F8;
u8&=(rex.w?0x3f:0x0f);
u8&=0x0f;
IFX(X_CF) {
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
}
@@ -2740,7 +2793,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
GETEW(x1, 1);
u8 = F8;
u8&=(rex.w?0x3f:0x0f);
u8&=0x0f;
IFX(X_CF) {
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
}
@@ -2756,7 +2809,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
GETEW(x1, 1);
u8 = F8;
u8&=(rex.w?0x3f:0x0f);
u8&=0x0f;
IFX(X_CF) {
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
}
@@ -2783,7 +2836,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
wback = 0;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
LDH(x4, x3, fixedaddress);
@@ -2924,10 +2977,12 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGW(x1);
GETEW(x2, 0);
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);
if (!(MODREG && wback == u8)) {
SUBw_REG(gd, ed, gd); // the old Ew is the sum minus Gw
BFIx(u8, gd, 0, 16);
}
break;
case 0xC2:
INST_NAME("CMPPD Gx, Ex, Ib");
@@ -3008,6 +3063,40 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
break;
case 0xC7:
nextop = F8;
if (MODREG) switch ((nextop >> 3) & 7) {
case 6:
case 7:
if (((nextop >> 3) & 7) == 7) {
INST_NAME("RDSEED Ew");
} else {
INST_NAME("RDRAND Ew");
}
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
GETEW(x2, 0);
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if (cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
} else {
CALL(const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
EWBACKW(x1);
break;
default:
DEFAULT;
} else {
DEFAULT;
}
break;
case 0xC8:
case 0xC9:
case 0xCA:
+9 -20
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -114,7 +115,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("LOCK CMPXCHG Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
UXTHw(x6, xRAX);
UXTHw(x5, xRAX);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(!ALIGNED_ATOMICH) {
if(cpuext.uscat) {
@@ -128,12 +129,12 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
// Aligned version
if(cpuext.atomics) {
MOVw_REG(x1, x6);
MOVw_REG(x1, x5);
CASALH(x1, gd, wback);
} else {
MARKLOCK;
LDAXRH(x1, wback);
CMPSw_REG(x6, x1);
CMPSw_REG(x5, x1);
B_MARK(cNE);
// EAX == Ed
STLXRH(x4, gd, wback);
@@ -148,7 +149,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
LDAXRB(x3, wback); // dummy read, to arm the write...
SUBw_UXTB(x3, x3, x1);
CBNZw_MARK3(x3);
CMPSw_REG(x6, x1);
CMPSw_REG(x5, x1);
B_MARK(cNE);
// EAX == Ed
STLXRB(x4, gd, wback);
@@ -157,7 +158,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
MARK;
// Common part (and fallback for EAX != Ed)
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
UFLAG_IF {emit_cmp16(dyn, ninst, x5, x1, x3, x4, x2);}
BFIx(xRAX, x1, 0, 16);
}
break;
@@ -210,11 +211,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGW(x5);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
@@ -361,11 +358,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, (uint16_t)i16);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
@@ -386,11 +379,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, (uint16_t)i16);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRH(x1, wback);
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+81 -22
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stddef.h>
#include <stdio.h>
#include <signal.h>
@@ -12,6 +13,11 @@
#include "dynarec_arm64_arch.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_native.h"
#include "custommem.h"
#include "khash.h"
KHASH_SET_INIT_INT64(lrcpc)
static kh_lrcpc_t *lrcpc = NULL;
//order might be important, so define SUPER for the right one
#define SUPER() \
@@ -67,6 +73,7 @@ typedef struct arch_arch_s
SUPER()
#undef GO
uint16_t unaligned:1;
uint16_t lrcpc:1;
uint16_t seq:10; // how many instruction on the same values
} arch_arch_t;
@@ -76,6 +83,7 @@ typedef struct arch_build_s
SUPER()
#undef GO
uint8_t unaligned;
uint8_t lrcpc;
#define GO(A) arch_##A##_t A##_;
SUPER()
#undef GO
@@ -91,16 +99,18 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
arch->flags = 1;
arch->flags_.defered = (dyn->insts[ninst].f_entry!=status_none && dyn->insts[ninst].f_entry!=status_none_pending);
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
arch->flags_.vf = flags&NF_VF;
arch->flags_.nf = flags&NF_SF;
arch->flags_.eq = flags&NF_EQ;
arch->flags_.cf = flags&NF_CF;
arch->flags_.vf = !!(flags&NF_VF);
arch->flags_.nf = !!(flags&NF_SF);
arch->flags_.eq = !!(flags&NF_EQ);
arch->flags_.cf = !!(flags&NF_CF);
if(arch->flags_.cf)
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
arch->flags_.pf_v = flags&NF_PF_V;
arch->flags_.pf_v = !!(flags&NF_PF_V);
}
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
// opcode has lrcpc opcode in it
arch->lrcpc = dyn->insts[ninst].has_lrcpc;
if(!noarch) {
// got through all naoncache to gather regs assignments
if(dyn->use_x87 || dyn->use_mmx || dyn->use_xmm || dyn->use_ymm) {
@@ -120,29 +130,29 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
arch->ymm = 1;
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
idx = i;
if(idx>=EMM0 && idx<=EMM0+8)
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);
arch->ymm_.ymm_pos |= (uint64_t)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);
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);
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);
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:
@@ -162,7 +172,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
}
}
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned + arch->lrcpc;
}
static int sizeof_arch(arch_arch_t* arch)
@@ -217,6 +227,7 @@ static void build_next(arch_arch_t* arch, arch_build_t* build)
SUPER()
#undef GO
arch->unaligned = build->unaligned;
arch->lrcpc = build->lrcpc;
arch->seq = 0;
void* p = ((void*)arch)+sizeof(arch_arch_t);
#define GO(A) \
@@ -309,6 +320,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
if(flags->defered) {
CHECK_FLAGS(emu);
//return;
} else {
emu->df = d_none;
}
if(flags->nf) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
@@ -358,12 +371,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
for(int i=0; i<16; ++i) {
if(fpsimd && (ymm->ymm>>i)&1) {
int idx = (ymm->ymm_pos>>(i*4))&0xf;
if(i>7) {
idx = SCRATCH0 + i - 8;
} else {
idx = EMM0 + i;
}
int pos = (ymm->ymm_pos>>(i*4))&0xf;
int idx = (pos>7) ? (SCRATCH0 + pos - 8) : (EMM0 + pos);
emu->ymm[i].u128 = fpsimd->vregs[idx];
}
if(ymm->ymm0&(1<<i))
@@ -380,10 +389,10 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
}
if(x87) {
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
emu->top -= x87->delta;
if (x87->delta) emu->top = (emu->top - x87->delta) & 7;
for(int i=0; i<8; ++i) {
if(x87->x87&(1<<i)) {
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
int idx = EMM0 + ((x87->x87_pos>>(i*4))&0x0f);
int t = (x87->x87_type>>(i*2))&0x3;
switch (t) {
case X87_ST_F:
@@ -424,3 +433,53 @@ int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
}
return arch->unaligned;
}
int arch_lrcpc(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 = 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));
}
return arch->lrcpc;
}
void add_lrcpc_address(uintptr_t addr)
{
if(!lrcpc)
lrcpc = kh_init(lrcpc);
khint_t k;
int ret;
k = kh_put(lrcpc, lrcpc, addr, &ret); // just add
}
int is_addr_lrcpc(uintptr_t addr)
{
if(!lrcpc)
return 0;
khint_t k = kh_get(lrcpc, lrcpc, addr);
return (k==kh_end(lrcpc))?0:1;
}
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc)
{
add_lrcpc_address(x64pc);
if(db->to_delete)
return 2; // already marked
db->to_delete = 1; // mark block for deletion
MarkDynablock(db); // and mark it as dirty
if(BOX64ENV(showsegv)) printf_log(LOG_INFO, "Marked db %p as dirty, and address %p as avoid lrcpc\n", db, (void*)x64pc);
return 2; // marked, exit handling...
}
+6
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNAREC_ARM_ARCH_H__
#define __DYNAREC_ARM_ARCH_H__
@@ -21,4 +22,9 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
#endif
// get if instruction can be regenerated for unaligned access
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
// get if instruction has lrcpc so it can be regenerated without
int arch_lrcpc(dynablock_t* db, uintptr_t x64pc);
void add_lrcpc_address(uintptr_t addr);
int is_addr_lrcpc(uintptr_t addr);
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc);
#endif // __DYNAREC_ARM_ARCH_H__
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+12 -10
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -268,6 +269,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
UDF(0);
} else {
INST_NAME("VMOVNTPS Ex, Gx");
NOLRCPC();
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(vex.l) {
@@ -417,7 +419,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VANDQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x55:
INST_NAME("VANDNPS Gx, Vx, Ex");
@@ -427,7 +429,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VBICQ(v0, v1, v2);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x56:
INST_NAME("VORPS Gx, Vx, Ex");
@@ -437,7 +439,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VORRQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x57:
INST_NAME("VXORPS Gx, Vx, Ex");
@@ -447,7 +449,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VEORQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x58:
INST_NAME("VADDPS Gx, Vx, Ex");
@@ -477,7 +479,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if(!vex.l) YMM0(gd);
break;
case 0x59:
INST_NAME("VMULPS Gx, Vx, Ex");
@@ -507,7 +509,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if(!vex.l) YMM0(gd);
break;
case 0x5A:
INST_NAME("VCVTPS2PD Gx, Ex");
@@ -521,7 +523,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty(q0, -1, -1, -1);
FCVTL2(q0, v1);
} else YMM0(gd)
} else YMM0(gd);
FCVTL(v0, v1);
break;
case 0x5B:
@@ -532,7 +534,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(vex.l) {
GETGY_empty_EY(v0, v1);
SCVTQFS(v0, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x5C:
INST_NAME("VSUBPS Gx, Vx, Ex");
@@ -562,7 +564,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if(!vex.l) YMM0(gd);
break;
case 0x5D:
INST_NAME("VMINPS Gx, Vx, Ex");
@@ -606,7 +608,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if(!vex.l) YMM0(gd);
break;
case 0x5F:
INST_NAME("VMAXPS Gx, Vx, Ex");
+6 -9
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -253,15 +254,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
GETGD;
GETED(0);
GETVD;
UXTBw(x6, vd);
CMPSw_U12(x6, rex.w ? 64 : 32);
UXTBw(x5, vd);
CMPSw_U12(x5, rex.w ? 64 : 32);
CSETMxw(x2, cPL);
IFX(X_CF) {
BFIw(xFlags, x2, F_CF, 1);
}
MVNxw_REG(x2, x2); //prepare mask
B_MARK(cPL);
LSLxw_REG(x2, x2, x6);
LSLxw_REG(x2, x2, x5);
MARK;
need_tst = 0;
IFX(X_ZF) need_tst = 1;
@@ -326,12 +327,8 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
IFX(X_CF) BFCw(xFlags, F_CF, 1);
IFX(X_OF) {
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else { BFCw(xFlags, F_SF, 1); }
}
IFX(X_OF) BFCw(xFlags, F_OF, 1);
IFX(X_SF) BFCw(xFlags, F_SF, 1);
break;
default:
+9 -6
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -243,6 +244,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x2B:
INST_NAME("VMOVNTPD Ex,Gx");
NOLRCPC();
nextop = F8;
GETG;
if(MODREG) {
@@ -321,7 +323,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VANDQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x55:
INST_NAME("VANDNPD Gx, Vx, Ex");
@@ -331,7 +333,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VBICQ(v0, v1, v2);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x56:
INST_NAME("VORPD Gx, Vx, Ex");
@@ -341,7 +343,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VORRQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x57:
INST_NAME("VXORPD Gx, Vx, Ex");
@@ -351,7 +353,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VEORQ(v0, v2, v1);
} else YMM0(gd)
} else YMM0(gd);
break;
case 0x58:
INST_NAME("VADDPD Gx, Vx, Ex");
@@ -413,7 +415,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if(!vex.l) YMM0(gd);
break;
case 0x5A:
INST_NAME("VCVTPD2PS Gx, Ex");
@@ -441,7 +443,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x5B:
INST_NAME("VCVTPS2DQ Gx, Ex");
nextop = F8;
u8 = sse_setround(dyn, ninst, x1, x2, x6);
u8 = sse_setround(dyn, ninst, x3, x2, x4); // the address below can use x2 and x3, x4 keeps the old FPCR
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
@@ -1783,6 +1785,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
break;
case 0xE7:
INST_NAME("VMOVNTDQ Ex,Gx");
NOLRCPC();
nextop = F8;
GETG;
if(MODREG) {
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -358,7 +359,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0x13:
INST_NAME("VCVTPH2PS Gx, Ex");
nextop = F8;
GETEX_Y(v1, 0, 0);
if(vex.l) {GETEX_Y(v1, 0, 0);} else {GETEX64(v1, 0, 0);}
GETGX_empty(v0);
if(vex.l && v0==v1) {
q1 = fpu_get_scratch(dyn, ninst);
@@ -642,6 +643,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
break;
case 0x2A:
INST_NAME("VMOVNTDQA Gx, Ex");
NOLRCPC();
nextop = F8;
GETG;
if(MODREG) {
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -162,7 +163,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
} else {
s0 = -1;
v1 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 1);
}
u8 = F8;
GETVX(v2, 0);
@@ -509,17 +510,17 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
u8 = F8;
if(u8&4) {
s0 = sse_setround(dyn, ninst, x1, x2, x6);
s0 = sse_setround(dyn, ninst, x1, x2, x5);
} else {
u8&=3;
if(u8==1) u8=2;
else if(u8==2) u8=1;
MRS_fpcr(x1); // get fpscr
MOV32w(x2, u8);
MOVx_REG(x6, x1);
MOVx_REG(x5, x1);
BFIx(x1, x2, 22, 2); // inject new round
MSR_fpcr(x1); // put new fpscr
s0 = x6;
s0 = x5;
}
FCVTN16(v1, v0);
if(vex.l) {
+10 -8
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -227,7 +228,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x58:
@@ -259,7 +260,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x59:
INST_NAME("VMULSD Gx, Vx, Ex");
@@ -309,7 +310,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5C:
@@ -341,7 +342,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5D:
INST_NAME("VMINSD Gx, Vx, Ex");
@@ -356,7 +357,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
YMM0(gd);
break;
case 0x5E:
INST_NAME("VDIVSD Gx, Vx, Ex");
@@ -387,7 +388,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5F:
INST_NAME("VMAXSD Gx, Vx, Ex");
@@ -401,7 +402,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
YMM0(gd);
break;
case 0x70:
@@ -585,11 +586,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0xE6:
INST_NAME("VCVTPD2DQ Gx, Ex");
nextop = F8;
u8 = sse_setround(dyn, ninst, x1, x2, x6);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETEX_Y(v1, 0, 0);
GETGX_empty(v0);
// after the address, so x2 can keep the old FPCR
u8 = sse_setround(dyn, ninst, x4, x5, x2);
if(!BOX64ENV(dynarec_fastround) || vex.l)
d0 = fpu_get_scratch(dyn, ninst);
} else {
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+8 -6
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -294,7 +295,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x59:
INST_NAME("VMULSS Gx, Vx, Ex");
@@ -325,7 +326,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5A:
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
@@ -404,7 +405,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5D:
INST_NAME("VMINSS Gx, Vx, Ex");
@@ -418,7 +419,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
YMM0(gd);
break;
case 0x5E:
INST_NAME("VDIVSS Gx, Vx, Ex");
@@ -449,7 +450,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
YMM0(gd);
break;
case 0x5F:
INST_NAME("VMAXSS Gx, Vx, Ex");
@@ -463,7 +464,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
YMM0(gd);
break;
case 0x6F:
@@ -550,6 +551,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
} else {
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
NOLRCPC();
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
for(int i=0; i<16; ++i) {
VST1_8(v0, i, i?x1:wback);
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+2 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include <string.h>
@@ -124,7 +125,7 @@ uintptr_t getConst(arm64_consts_t which)
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len_imm8w;
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
case const_x64test_step: return (uintptr_t)x64test_step;
case const_printtrace: return (uintptr_t)PrintTrace;
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNAREC_ARM64_CONSTS__
#define __DYNAREC_ARM64_CONSTS__
#include <stdint.h>
+196 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -30,12 +31,14 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t u8;
int64_t fixedaddress;
int unscaled;
int v1, v2;
int v1, v2, s5, s6;
int s0;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(s5);
MAYUSE(s6);
if(MODREG)
switch(nextop) {
@@ -53,9 +56,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FADDS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -75,9 +94,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FMULS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -134,9 +169,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FSUBS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -156,9 +207,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FSUBS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -178,9 +245,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FDIVS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -200,9 +283,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FDIVS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -222,10 +321,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, s0, s5);
}
FADDS(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, s0, s5);
}
FADDD(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -240,10 +355,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, s0, s5);
}
FMULS(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, s0, s5);
}
FMULD(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -287,10 +418,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, s0, s5);
}
FSUBS(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, s0, s5);
}
FSUBD(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -305,10 +452,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(s0, v1, s5);
}
FSUBS(v1, s0, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(s0, v1, s5);
}
FSUBD(v1, s0, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -323,10 +486,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, s0, s5);
}
FDIVS(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, s0, s5);
}
FDIVD(v1, v1, s0);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -341,10 +520,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(s0, v1, s5);
}
FDIVS(v1, s0, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
}
} else {
FCVT_D_S(s0, s0);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(s0, v1, s5);
}
FDIVD(v1, s0, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
+15 -4
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -236,11 +237,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
&& PK(2)==0xD9 && PK(3)==0xF3
) {
MESSAGE(LOG_DUMP, "Hack for FLD1 FLD1 FPATAN");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
FTABLE64(v1, PI/4.0);
addr+=4;
} else {
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v1, 0b01110000);
} else {
@@ -275,7 +276,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xEE:
INST_NAME("FLDZ");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
VEOR(v1, v1, v1);
break;
@@ -302,7 +303,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
u8 = F8;
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
} else {
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, NEON_CACHE_ST_F);
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v2, 0b01110000);
} else {
@@ -449,9 +450,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FCMPS_0(v1);
FSQRTS(v1, v1);
v2 = fpu_get_scratch(dyn, ninst);
MOV32w(x3, X87_REAL_INDEFINITE_FLOAT);
FMOVSw(v2, x3);
FCSELS(v1, v2, v1, cMI); // MI: less than, not unordered
} else {
FCMPD_0(v1);
FSQRTD(v1, v1);
v2 = fpu_get_scratch(dyn, ninst);
MOV64x(x3, X87_REAL_INDEFINITE_DOUBLE);
FMOVDx(v2, x3);
FCSELD(v1, v2, v1, cMI); // MI: less than, not unordered
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
+68 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -28,7 +29,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t ed;
uint8_t wback;
uint8_t u8;
int v1, v2;
int v1, v2, s5, s6;
int d0;
int s0;
int64_t fixedaddress;
@@ -149,7 +150,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -164,7 +173,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -202,7 +219,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -217,7 +242,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -230,9 +263,35 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(BOX64ENV(dynarec_div0)) {
FCMPD_0(v2);
B_MARK3(cNE);
LDRH_U12(x5, xEmu, offsetof(x64emu_t, cw));
TBNZ_MARK2(x5, 2); // set SW.ZE flag if bit 2 is set
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
MARK2;
LDRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
MOV32w(x4, 0x4); // ZE flag
ORRw_REG(x5, x5, x4);
STRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
MARK3;
}
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -247,7 +306,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
+13 -2
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -275,7 +276,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
NOTEST(x5);
// the FLD is immediatly followed by an FSTP
LDRx_U12(x5, ed, 0);
LDRH_U12(x6, ed, 8);
LDRH_U12(x4, ed, 8);
// no persistant scratch register, so unrool both instruction here...
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
nextop = F8; // 0xDB or rex
@@ -287,7 +288,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8; //modrm
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
STRx_U12(x5, ed, 0);
STRH_U12(x6, ed, 8);
STRH_U12(x4, ed, 8);
} else {
if(BOX64ENV(x87_no80bits)) {
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
@@ -356,11 +357,21 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
B_MARK3_nocond;
// denormals
#ifdef BOX64EC
// no x6 (guest R9) and x2 can be the address: x3 is free here (exp11 == 0), at the cost of the MOV
CLZx(x3, x1);
ADDw_U12(x3, x3, 1); // "one"
SUBw_REG(x4, x4, x3); // x4 = exp16
ORRw_REG(x4, x4, x5); // x4 = sign | exp16
LSLx_REG(x5, x1, x3); // x5 = mantisse
MOVw_REG(x3, x4);
#else
CLZx(x6, x1);
ADDw_U12(x6, x6, 1); // "one"
SUBw_REG(x3, x4, x6); // x3 = exp16
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
LSLx_REG(x5, x1, x6); // x5 = mantisse
#endif
MARK3;
STRx_U12(x5, wback, 0);
STRH_U12(x3, wback, 8);
+146 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t u8;
int64_t fixedaddress;
int unscaled;
int v1, v2;
int v1, v2, s5, s6;
MAYUSE(v2);
MAYUSE(v1);
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FADDS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -73,9 +90,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FMULS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -132,9 +165,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FSUBS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -154,9 +203,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FSUBS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -176,9 +241,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FDIVS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FDIVS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -219,7 +316,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -232,7 +337,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -264,7 +377,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -277,7 +398,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -290,7 +419,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -303,7 +440,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VLD64(v2, wback, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+170 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t u8;
int64_t fixedaddress;
int unscaled;
int v1, v2;
int v1, v2, s5, s6;
MAYUSE(v2);
MAYUSE(v1);
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FADDS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -74,9 +91,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FMULS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -129,9 +162,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FSUBS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -152,9 +201,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FSUBS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -175,9 +240,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v2, v1, s5);
}
FDIVS(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_S(v1, v2, s5);
}
FDIVS(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
}
} else {
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
@@ -221,8 +318,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 1:
INST_NAME("FIMUL ST0, word[ED]");
@@ -233,8 +342,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 2:
INST_NAME("FICOM ST0, word[ED]");
@@ -270,8 +391,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 5:
INST_NAME("FISUBR ST0, word[ED]");
@@ -282,8 +415,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 6:
INST_NAME("FIDIV ST0, word[ED]");
@@ -294,8 +439,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v1, v2, s5);
}
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 7:
INST_NAME("FIDIVR ST0, word[ED]");
@@ -306,8 +463,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SXTL_16(v2, v2);
SXTL_32(v2, v2);
SCVTFDD(v2, v2);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(!BOX64ENV(dynarec_fastnan)) {
s5 = fpu_get_scratch(dyn, ninst);
s6 = fpu_get_scratch(dyn, ninst);
X87_ARITH_NAN_START_D(v2, v1, s5);
}
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
}
X87_CHECK_PRECISION(v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
}
return addr;
+2 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -127,7 +128,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ew");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
LDSHw(x1, wback, fixedaddress);
if(ST_IS_F(0)) {
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+47 -26
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1000,9 +1001,13 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
}
} else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(xFlags, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF) {
ORRxw_REG(s3, s1, s2); // s3 = op1 | op2
@@ -1143,9 +1148,13 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
}
} else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(xFlags, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF | X_OF) {
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
@@ -1207,9 +1216,13 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
}
} else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(xFlags, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, xFlags, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF | X_OF) {
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
@@ -1331,9 +1344,13 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
} else {
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(s4, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF) {
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
@@ -1480,9 +1497,13 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
} else {
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(s4, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF|X_OF|X_CF) {
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
@@ -1545,9 +1566,13 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
} else {
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C, bit 29
MSR_nzcv(s3); // load CC into ARM CF
if(cpuext.flagm)
RMIF(s4, 63, 0b0010);
else {
MRS_nzcv(s3);
BFIx(s3, s4, 29, 1); // set C, bit 29
MSR_nzcv(s3); // load CC into ARM CF
}
}
IFX(X_AF|X_OF|X_CF) {
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
@@ -1727,10 +1752,8 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
}
IFX(X_AF) {
ORRw_REG(s3, s3, s1); // bc = op1 | res
IFX(X_AF) {
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
@@ -1783,10 +1806,8 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
}
IFX(X_AF) {
ORRw_REG(s3, s3, s1); // bc = op1 | res
IFX(X_AF) {
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
+39 -13
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1274,9 +1275,14 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
}
// emit RCL32/RCL64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
#ifdef BOX64EC
int s5 = s3; // no x6 (guest R9), so s3 is reused and the new CF waits in F_res2
#else
int s5 = x6;
#endif
if(BOX64ENV(cputype)) {
IFX(X_OF|X_CF) {
@@ -1291,6 +1297,11 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
LSRxw_REG(s3, s1, s4);
}
}
#ifdef BOX64EC
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
BFIw(xFlags, s3, F_res2, 1);
}
#endif
if(!BOX64ENV(cputype))
IFX(X_OF) {
LSRxw(s4, s1, rex.w?62:30);
@@ -1318,15 +1329,27 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
ORRxw_REG(s1, s1, s4);
}
IFX(X_CF) {
#ifdef BOX64EC
BFXILw(xFlags, xFlags, F_res2, 1);
#else
BFIw(xFlags, s3, F_CF, 1);
#endif
}
IFX2(X_OF, && BOX64ENV(cputype)) {
#ifdef BOX64EC
UBFXw(s3, xFlags, F_res2, 1);
#endif
EORxw_REG_LSR(s3, s3, s1, rex.w?63:31);
BFIw(xFlags, s3, F_OF, 1);
}
#ifdef BOX64EC
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
BFCw(xFlags, F_res2, 1);
}
#endif
}
// emit RCR32/RCR64 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
// emit RCR32/RCR64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
@@ -1348,15 +1371,15 @@ void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
/*else*/
{
LSRxw_REG(s5, s1, s2);
UBFXw(s4, xFlags, 0, 1);
LSRxw_REG(s4, s1, s2);
MOVZw(s3, (rex.w?64:32));
SUBx_REG(s3, s3, s2);
LSLxw_REG(s4, s4, s3);
ORRxw_REG(s5, s5, s4);
UBFXw(s2, xFlags, 0, 1); // s2 is not needed anymore
LSLxw_REG(s2, s2, s3);
ORRxw_REG(s4, s4, s2);
ADDx_U12(s3, s3, 1);
LSLxw_REG(s1, s1, s3);
ORRxw_REG(s1, s1, s5);
ORRxw_REG(s1, s1, s4);
}
IFX(X_CF) {
BFXILw(xFlags, xFlags, F_res2, 1);
@@ -1622,8 +1645,9 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
c&=0x1f;
IFX(X_PEND) {
MOV32w(s3, c);
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
SET_DF(s4, d_shrd16);
} else {
SET_DFNONE();
@@ -1665,7 +1689,8 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
{
IFX(X_PEND) {
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
// same flags computation as with shl64/shl32
SET_DF(s4, d_shrd16);
} else {
@@ -1714,8 +1739,9 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
c&=0x1f;
IFX(X_PEND) {
MOV32w(s3, c);
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
SET_DF(s4, d_shld16);
} else {
SET_DFNONE();
@@ -1769,12 +1795,12 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
{
IFX(X_PEND) {
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
SET_DF(s4, d_shld16);
} else {
SET_DFNONE();
}
uint8_t mask = X_CF;
if(BOX64ENV(cputype)) {
IFX(X_CF|X_OF) {
MOV32w(s3, 16);
+46 -45
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -309,8 +310,8 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
}
}
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
IFX_PENDOR0 {
@@ -348,12 +349,12 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s3, s5);
emit_pf(dyn, ninst, s3, s4);
}
}
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
int mask = convert_bitmask_xw(c);
@@ -397,12 +398,12 @@ void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s3, s5);
emit_pf(dyn, ninst, s3, s4);
}
}
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s2);
IFX_PENDOR0 {
@@ -411,8 +412,8 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
SET_DFNONE();
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 16);
ANDSw_REG_LSL(s5, s5, s2, 16);
LSLw(s3, s1, 16);
ANDSw_REG_LSL(s3, s3, s2, 16);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
@@ -432,24 +433,24 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
}
}
IFX(X_PF|X_PEND) {
LSRw(s5, s5, 16);
LSRw(s3, s3, 16);
}
} else {
ANDw_REG(s5, s1, s2); // res = s1 & s2
ANDw_REG(s3, s1, s2); // res = s1 & s2
}
IFX(X_AF) {
BFCw(xFlags, F_AF, 1);
}
IFX_PENDOR0 {
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_PF) {
emit_pf(dyn, ninst, s5, s4);
emit_pf(dyn, ninst, s3, s4);
}
}
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
{
MAYUSE(s1);
int mask = 0;
@@ -459,13 +460,13 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
SET_DFNONE();
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 16);
LSLw(s3, s1, 16);
mask = convert_bitmask_w(c<<16);
if(mask) {
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
} else {
MOV32w(s3, c);
ANDSw_REG_LSL(s5, s5, s3, 16);
MOV32w(s4, c);
ANDSw_REG_LSL(s3, s3, s4, 16);
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
@@ -486,30 +487,30 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
}
}
IFX(X_PF|X_PEND) {
LSRw(s5, s5, 16);
LSRw(s3, s3, 16);
}
} else {
mask = convert_bitmask_w(c);
if(mask) {
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
} else {
MOV32w(s5, c);
ANDw_REG(s5, s1, s5); // res = s1 & s2
MOV32w(s3, c);
ANDw_REG(s3, s1, s3); // res = s1 & s2
}
}
IFX(X_AF) {
BFCw(xFlags, F_AF, 1);
}
IFX_PENDOR0 {
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_PF) {
emit_pf(dyn, ninst, s5, s4);
emit_pf(dyn, ninst, s3, s4);
}
}
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
// emit TEST8 instruction, from test s1, s2, using s3 and s4 as scratch
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MAYUSE(s1); MAYUSE(s2);
IFX_PENDOR0 {
@@ -518,8 +519,8 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
SET_DFNONE();
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 24);
ANDSw_REG_LSL(s5, s5, s2, 24);
LSLw(s3, s1, 24);
ANDSw_REG_LSL(s3, s3, s2, 24);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
@@ -539,24 +540,24 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
}
}
IFX(X_PF|X_PEND) {
LSRw(s5, s5, 24);
LSRw(s3, s3, 24);
}
} else {
ANDw_REG(s5, s1, s2); // res = s1 & s2
ANDw_REG(s3, s1, s2); // res = s1 & s2
}
IFX(X_AF) {
BFCw(xFlags, F_AF, 1);
}
IFX_PENDOR0 {
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_PF) {
emit_pf(dyn, ninst, s5, s4);
emit_pf(dyn, ninst, s3, s4);
}
}
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
{
MAYUSE(s1);
int mask = 0;
@@ -566,13 +567,13 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
SET_DFNONE();
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 24);
LSLw(s3, s1, 24);
mask = convert_bitmask_w(c<<24);
if(mask) {
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
} else {
MOV32w(s3, c);
ANDSw_REG_LSL(s5, s5, s3, 24);
MOV32w(s4, c);
ANDSw_REG_LSL(s3, s3, s4, 24);
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
@@ -593,24 +594,24 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
}
}
IFX(X_PF|X_PEND) {
LSRw(s5, s5, 24);
LSRw(s3, s3, 24);
}
} else {
mask = convert_bitmask_w(c);
if(mask) {
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
} else {
MOV32w(s5, c);
ANDw_REG(s5, s1, s5); // res = s1 & s2
MOV32w(s3, c);
ANDw_REG(s3, s1, s3); // res = s1 & s2
}
}
IFX(X_AF) {
BFCw(xFlags, F_AF, 1);
}
IFX_PENDOR0 {
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_PF) {
emit_pf(dyn, ninst, s5, s4);
emit_pf(dyn, ninst, s3, s4);
}
}
+20 -44
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -238,28 +239,28 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("LOCK CMPXCHG Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGB(x1);
UBFXx(x6, xRAX, 0, 8);
UBFXx(x5, xRAX, 0, 8);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(cpuext.atomics) {
UFLAG_IF {
MOVw_REG(x2, x6);
CASALB(x6, gd, wback);
emit_cmp8(dyn, ninst, x2, x6, x3, x4, x5);
MOVw_REG(x2, x5);
CASALB(x5, gd, wback);
emit_cmp8(dyn, ninst, x2, x5, x3, x4, x1);
} else {
CASALB(x6, gd, wback);
CASALB(x5, gd, wback);
}
BFIx(xRAX, x6, 0, 8);
BFIx(xRAX, x5, 0, 8);
} else {
MARKLOCK;
LDAXRB(x2, wback);
CMPSxw_REG(x6, x2);
CMPSxw_REG(x5, x2);
B_MARK(cNE);
// EAX == Ed
STLXRB(x4, gd, wback);
CBNZx_MARKLOCK(x4);
// done
MARK;
UFLAG_IF {emit_cmp8(dyn, ninst, x6, x2, x3, x4, x5);}
UFLAG_IF {emit_cmp8(dyn, ninst, x5, x2, x3, x4, x1);}
BFIx(xRAX, x2, 0, 8);
}
}
@@ -282,7 +283,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
UFLAG_IF { MOVxw_REG(x6, xRAX); }
UFLAG_IF { MOVxw_REG(x5, xRAX); }
if(!ALIGNED_ATOMICxw) {
if(cpuext.uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
@@ -344,7 +345,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
MARK;
UFLAG_IF {
emit_cmp32(dyn, ninst, rex, x6, x1, x3, x4, x5);
emit_cmp32(dyn, ninst, rex, x5, x1, x3, x4, x2);
}
}
break;
@@ -371,7 +372,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// Will fetch only 1 byte, to avoid alignment issue
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
ASRxw(x1, gd, 3); // r1 = (gd>>3)
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
ed = x1;
@@ -547,7 +548,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// Will fetch only 1 byte, to avoid alignment issue
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
ASRxw(x1, gd, 3); // r1 = (gd>>3)
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
ed = x1;
@@ -785,7 +786,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
B_MARK3_nocond;
MARKSEG;
STLXRB(x4, x5, wback); //write back
STLXRB(x4, x2, wback); //write back
CBNZx_MARK2(x4);
MOVxw_REG(xRAX, x2);
MOVxw_REG(xRDX, x3);
@@ -822,11 +823,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGB(x2);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRB(x1, wback);
emit_adc8(dyn, ninst, x1, x2, x4, x5);
STLXRB(x4, x1, wback);
@@ -847,11 +844,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRxw(x1, wback);
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
STLXRxw(x4, x1, wback);
@@ -869,7 +862,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
INST_NAME("LOCK AND Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
GETGB(x5);
if(cpuext.atomics) {
@@ -1107,11 +1099,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
u8 = F8;
wb1 = 1;
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRB(x1, wback);
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
STLXRB(x3, x1, wback);
@@ -1132,11 +1120,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
u8 = F8;
wb1 = 1;
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRB(x1, wback);
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
STLXRB(x3, x1, wback);
@@ -1369,11 +1353,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
MOV64xw(x5, i64);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRxw(x1, wback);
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
@@ -1394,11 +1374,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
MOV64xw(x5, i64);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
MARKLOCK_SAVE_FLAGS();
LDAXRxw(x1, wback);
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
+32 -5
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -68,6 +69,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) {
ed = (nextop&7)+ (rex.b<<3);
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
@@ -237,6 +239,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(q0, 1);
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(d0, 0, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
@@ -247,10 +251,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(v1, v0, v1); // forget it in any input was a NAN already
SHL_64(v1, v1, 63); // only keep the sign bit
VORR(d1, d1, v1); // NAN -> -NAN
VMOVeD(q0, 0, d1, 0);
} else if(XMMH_UNNEEDED(gd)) {
FSQRTD(q0, d0); // upper 64 dead: compute in place, skip preserve
} else {
FSQRTD(d1, d0);
VMOVeD(q0, 0, d1, 0);
}
VMOVeD(q0, 0, d1, 0);
break;
case 0x58:
@@ -259,6 +266,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSD(d0, 0, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -277,10 +286,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeD(d1, 0, v1, 0);
} else if(XMMH_UNNEEDED(gd)) {
FADDD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
} else {
FADDD(v1, d1, d0); // the high part of the vector is erased...
VMOVeD(d1, 0, v1, 0);
}
VMOVeD(d1, 0, v1, 0);
break;
case 0x59:
INST_NAME("MULSD Gx, Ex");
@@ -288,6 +300,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSD(d0, 0, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -306,10 +320,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeD(d1, 0, v1, 0);
} else if(XMMH_UNNEEDED(gd)) {
FMULD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
} else {
FMULD(v1, d1, d0);
VMOVeD(d1, 0, v1, 0);
}
VMOVeD(d1, 0, v1, 0);
break;
case 0x5A:
INST_NAME("CVTSD2SS Gx, Ex");
@@ -333,6 +350,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSD(d0, 0, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -351,10 +370,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeD(d1, 0, v1, 0);
} else if(XMMH_UNNEEDED(gd)) {
FSUBD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
} else {
FSUBD(v1, d1, d0);
VMOVeD(d1, 0, v1, 0);
}
VMOVeD(d1, 0, v1, 0);
break;
case 0x5D:
INST_NAME("MINSD Gx, Ex");
@@ -372,6 +394,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(v0, 1);
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
MARK_XMM_SCALAR(gd);
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -390,10 +414,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(d1, v2, d0); // where src1 was NaN, use QNaN(src1)
VMOVeD(v0, 0, d1, 0);
} else if(XMMH_UNNEEDED(gd)) {
FDIVD(v0, v0, v1); // upper 64 dead: compute in place, skip preserve
} else {
FDIVD(d1, v0, v1);
VMOVeD(v0, 0, d1, 0);
}
VMOVeD(v0, 0, d1, 0);
break;
case 0x5F:
INST_NAME("MAXSD Gx, Ex");
+60 -6
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -52,6 +53,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(MODREG) {
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3)); // reg-reg move reads only low-32 of src
VMOVeS(v0, 0, q0, 0);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
@@ -65,6 +67,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
MARK_XMM_SCALAR_SINGLE(gd); // store reads only low-32 of Gx, upper-96 untouched
if(MODREG) {
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
VMOVeS(q0, 0, v0, 0);
@@ -236,6 +239,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(q0, 1);
d1 = fpu_get_scratch(dyn, ninst);
GETEXSS(d0, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
@@ -246,16 +251,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(v1, v0, v1); // forget it in any input was a NAN already
VSHL_32(v1, v1, 31); // only keep the sign bit
VORR(d1, d1, v1); // NAN -> -NAN
VMOVeS(q0, 0, d1, 0);
} else if(XMMS_UNNEEDED(gd)) {
FSQRTS(q0, d0); // upper 96 dead: compute in place, skip preserve
} else {
FSQRTS(d1, d0);
VMOVeS(q0, 0, d1, 0);
}
VMOVeS(q0, 0, d1, 0);
break;
case 0x52:
INST_NAME("RSQRTSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEXSS(v1, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
@@ -273,6 +283,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGX(v0, 1);
GETEXSS(v1, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
d0 = fpu_get_scratch(dyn, ninst);
FMOVS_8(d0, 0b01110000); //1.0f
FDIVS(d0, d0, v1);
@@ -285,6 +297,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSS(d0, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -304,10 +318,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeS(d1, 0, v1, 0);
} else if(XMMS_UNNEEDED(gd)) {
FADDS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
} else {
FADDS(v1, d1, d0); // the high part of the vector is erased...
VMOVeS(d1, 0, v1, 0);
}
VMOVeS(d1, 0, v1, 0);
break;
case 0x59:
INST_NAME("MULSS Gx, Ex");
@@ -315,6 +332,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSS(d0, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -334,10 +353,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeS(d1, 0, v1, 0);
} else if(XMMS_UNNEEDED(gd)) {
FMULS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
} else {
FMULS(v1, d1, d0); // the high part of the vector is erased...
VMOVeS(d1, 0, v1, 0);
}
VMOVeS(d1, 0, v1, 0);
break;
case 0x5A:
INST_NAME("CVTSS2SD Gx, Ex");
@@ -399,6 +421,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSS(d0, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -418,16 +442,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeS(d1, 0, v1, 0);
} else if(XMMS_UNNEEDED(gd)) {
FSUBS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
} else {
FSUBS(v1, d1, d0); // the high part of the vector is erased...
VMOVeS(d1, 0, v1, 0);
}
VMOVeS(d1, 0, v1, 0);
break;
case 0x5D:
INST_NAME("MINSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEXSS(v1, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
FCMPS(v0, v1);
B_NEXT(cCC); //CC invert of CS: NAN or == or Gx > Ex
@@ -439,6 +468,26 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn, ninst);
GETEXSS(d0, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
if(BOX64ENV(dynarec_div0)) {
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
TBNZ_MARK2(x5, 9); // set ZE flag if bit 9 is set
FCMPS_0(d0);
B_MARK3(cNE);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
MARK2;
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
MOV32w(x4, 0x4); // ZE flag
ORRw_REG(x5, x5, x4);
STRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
MARK3;
}
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
@@ -458,16 +507,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
VMOVeS(d1, 0, v1, 0);
} else if(XMMS_UNNEEDED(gd)) {
FDIVS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
} else {
FDIVS(v1, d1, d0); // the high part of the vector is erased...
VMOVeS(d1, 0, v1, 0);
}
VMOVeS(d1, 0, v1, 0);
break;
case 0x5F:
INST_NAME("MAXSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEXSS(v1, 0, 0);
MARK_XMM_SCALAR_SINGLE(gd);
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
FCMPS(v1, v0);
B_NEXT(cCC); //CC: invert of CS: NAN or == or Ex > Gx
@@ -537,6 +591,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
NOLRCPC();
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
for(int i=0; i<16; ++i) {
VST1_8(v0, i, i?x1:wback);
@@ -767,7 +822,6 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETEXSD(v1, 0, 0);
GETGX_empty(v0);
d0 = fpu_get_scratch(dyn, ninst);
SXTL_32(v0, v1);
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
break;
+108 -77
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
@@ -28,6 +29,11 @@
// Get a FPU scratch reg
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
{
if(dyn->n.fpu_scratch >= 8) {
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU scratch registers at inst=%d\n", ninst);
dyn->abort = 1;
return SCRATCH0;
}
int ret = SCRATCH0 + dyn->n.fpu_scratch++;
if(dyn->n.ymm_used) {
printf_log(LOG_INFO, "Warning, getting a scratch register after getting some YMM at inst=%d", ninst);
@@ -44,6 +50,11 @@ int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
// Get 2 consicutive FPU scratch reg
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst)
{
if(dyn->n.fpu_scratch >= 7) {
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU double scratch registers at inst=%d\n", ninst);
dyn->abort = 1;
return SCRATCH0;
}
int ret = SCRATCH0 + dyn->n.fpu_scratch;
if(dyn->n.ymm_used) {
printf_log(LOG_INFO, "Warning, getting a double scratch register after getting some YMM at inst=%d", ninst);
@@ -76,12 +87,19 @@ void fpu_reset_scratch(dynarec_arm_t* dyn)
dyn->n.xmm_unneeded = 0;
dyn->n.ymm_unneeded = 0;
dyn->n.xmm_removed = 0;
dyn->n.xmm_scalar = 0;
dyn->n.xmm_scalar_single = 0;
}
// Get a x87 double reg
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
{
int i=X870;
while (dyn->n.fpuused[i]) ++i;
while (i<32 && dyn->n.fpuused[i]) ++i;
if(i==32) {
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU x87 registers at inst=%d\n", ninst);
dyn->abort = 1;
return X870;
}
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
// should only happens in step 0...
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[i].n); // mark as purged
@@ -109,7 +127,7 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
dyn->n.ymm_removed |= 1<<n;
if(t==NEON_CACHE_YMMW)
dyn->n.ymm_write |= 1<<n;
if(reg>SCRATCH0)
if(reg>=SCRATCH0)
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(n*4);
else
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(n*4);
@@ -429,7 +447,7 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
if(dyn->insts[ninst].n.stack_next) {
return 0;
}
for(int i=0; i<24; ++i)
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
if(!(
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
@@ -438,6 +456,8 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
return 0;
}
if(dyn->insts[ninst].ymm0_out)
return 0;
return 1;
}
@@ -638,49 +658,6 @@ void neoncacheUnwind(neoncache_t* cache)
cache->ymm_used = 0;
}
#define F8 *(uint8_t*)(addr++)
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
{
(void)dyn; (void)ninst;
uint32_t tested = (1<<parity)-1;
if((nextop&0xC0)==0xC0)
return 0; // direct register, no parity...
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
int sib_reg = (sib>>3)&7;
if((sib&0x7)==5) {
uint64_t tmp = F32S64;
if (sib_reg!=4) {
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
} else {
// just a constant...
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4 && parity<3)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
}
} else if((nextop&7)==5) {
uint64_t tmp = F32S64;
tmp+=addr+delta;
return (tmp&tested)?0:1;
} else {
return 0;
}
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
}
#undef F8
#undef F32S64
const char* getCacheName(int t, int n)
{
static char buff[20];
@@ -720,22 +697,22 @@ static register_mapping_t register_mappings[] = {
{ "bx", "x13" },
{ "bh", "x13" },
{ "bl", "x13" },
{ "rsi", "x14" },
{ "esi", "w14" },
{ "si", "x14" },
{ "sil", "x14" },
{ "rdi", "x15" },
{ "edi", "w15" },
{ "di", "x15" },
{ "dil", "x15" },
{ "rsp", "x16" },
{ "esp", "w16" },
{ "sp", "x16" },
{ "spl", "x16" },
{ "rbp", "x17" },
{ "ebp", "w17" },
{ "bp", "x17" },
{ "bpl", "x17" },
{ "rsp", "x14" },
{ "esp", "w14" },
{ "sp", "x14" },
{ "spl", "x14" },
{ "rbp", "x15" },
{ "ebp", "w15" },
{ "bp", "x15" },
{ "bpl", "x15" },
{ "rsi", "x16" },
{ "esi", "w16" },
{ "si", "x16" },
{ "sil", "x16" },
{ "rdi", "x17" },
{ "edi", "w17" },
{ "di", "x17" },
{ "dil", "x17" },
{ "r8", "x18" },
{ "r8d", "w18" },
{ "r8w", "x18" },
@@ -790,8 +767,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
return;
}
static char buf[4096];
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
static char buf[8192];
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)%d",
dyn->insts[ninst].x64.barrier,
dyn->insts[ninst].x64.state_flags,
df_status[dyn->f],
@@ -803,7 +780,11 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
dyn->insts[ninst].x64.use_flags,
dyn->insts[ninst].x64.need_before,
dyn->insts[ninst].x64.need_after,
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock);
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock,
dyn->insts[ninst].x64.strongmem);
if(dyn->insts[ninst].use_lrcpc || dyn->insts[ninst].has_lrcpc) {
length += sprintf(buf + length, " LRCPC:%d/%d", dyn->insts[ninst].use_lrcpc, dyn->insts[ninst].has_lrcpc);
}
if (dyn->insts[ninst].nat_flags_op) {
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
@@ -867,6 +848,12 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.xmm_needed) {
length += sprintf(buf + length, " xmmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_needed, dyn->insts[ninst].n.xmm_unneeded);
}
if (dyn->insts[ninst].n.xmmh_used || dyn->insts[ninst].n.xmmh_needed || dyn->insts[ninst].n.xmmh_unneeded) {
length += sprintf(buf + length, " xmmHused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmmh_used, dyn->insts[ninst].n.xmmh_needed, dyn->insts[ninst].n.xmmh_unneeded);
}
if (dyn->insts[ninst].n.xmms_used || dyn->insts[ninst].n.xmms_needed || dyn->insts[ninst].n.xmms_unneeded) {
length += sprintf(buf + length, " xmmSused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmms_used, dyn->insts[ninst].n.xmms_needed, dyn->insts[ninst].n.xmms_unneeded);
}
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.ymm_needed) {
length += sprintf(buf + length, " ymmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_needed, dyn->insts[ninst].n.ymm_unneeded);
}
@@ -909,7 +896,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
if (BOX64ENV(dynarec_perf_map) && (BOX64ENV(dynarec_perf_map_fd) != -1) && dyn->insts[ninst].size) {
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size, name);
}
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
}
@@ -1233,26 +1220,32 @@ static uint32_t getXYMMMask(dynarec_arm_t* dyn, int ninst)
return ret;
}
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
{
while(ninst>=0) {
// removed unneeded regs
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
// removed already needed from mask
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
// already handled
if(!mask_x && !mask_y) return;
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
// added the unneeded value
dyn->insts[ninst].n.xmm_needed |= mask_x;
dyn->insts[ninst].n.ymm_needed |= mask_y;
dyn->insts[ninst].n.xmmh_needed |= mask_xh;
dyn->insts[ninst].n.xmms_needed |= mask_xs;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i) {
int j = dyn->insts[ninst].pred[i];
// barrier or callret, value is needed
if(!(dyn->insts[j].x64.barrier&BARRIER_FLOAT)
&& !(dyn->insts[j].x64.has_callret))
propagateXYMMNeeded(dyn, j, mask_x, mask_y);
propagateXYMMNeeded(dyn, j, mask_x, mask_y, mask_xh, mask_xs);
}
if(dyn->insts[ninst].pred_sz)
ninst = dyn->insts[ninst].pred[0];
@@ -1265,25 +1258,31 @@ static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x,
}
}
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
{
while(ninst>=0) {
// removed needed regs
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
// removed already unneeded from mask
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
// already handled
if(!mask_x && !mask_y) return;
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
// barrier or callret, value is needed
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return;
if(dyn->insts[ninst].x64.has_callret) return;
// added the unneeded value
dyn->insts[ninst].n.xmm_unneeded |= mask_x;
dyn->insts[ninst].n.ymm_unneeded |= mask_y;
dyn->insts[ninst].n.xmmh_unneeded |= mask_xh;
dyn->insts[ninst].n.xmms_unneeded |= mask_xs;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y);
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y, mask_xh, mask_xs);
if(dyn->insts[ninst].pred_sz)
ninst = dyn->insts[ninst].pred[0];
else
@@ -1297,24 +1296,46 @@ void updateUneeded(dynarec_arm_t* dyn)
if(!dyn->use_xmm && !dyn->use_ymm)
return;
// Upper-64 liveness of the low 16 XMM, seeded here and propagated by the same
// needed/unneeded passes below used for whole-xmm and the ymm upper-128 lanes.
// A scalar SD op touches only the low 64, so it sits in xmm_scalar and is masked
// out of xmmh_used; every full-width reader keeps its bit and pins the upper lane
// live. An op may zero the upper in place (skipping the x86 upper-preserve) only
// where xmmh_unneeded proves the lane dead.
// xmms is the same, one dword lower: the upper-96 [127:32] used by scalar-single ops.
// A scalar SD op still reads [63:32], so only scalar-single ops (xmm_scalar_single) are
// masked out of xmms_used. An SS op may zero the upper-96 in place only where xmms_unneeded
// proves it dead.
for(int ninst=0; ninst<dyn->size; ++ninst) {
dyn->insts[ninst].n.xmmh_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar;
dyn->insts[ninst].n.xmmh_unneeded = dyn->insts[ninst].n.xmm_unneeded;
dyn->insts[ninst].n.xmms_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar_single;
dyn->insts[ninst].n.xmms_unneeded = dyn->insts[ninst].n.xmm_unneeded;
}
// first propagate the needed regs: those which are used and are not unneeded
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
uint16_t xmm_needed = dyn->insts[ninst].n.xmm_used&~dyn->insts[ninst].n.xmm_unneeded;
uint16_t ymm_needed = dyn->insts[ninst].n.ymm_used&~dyn->insts[ninst].n.ymm_unneeded;
uint16_t xmmh_needed = dyn->insts[ninst].n.xmmh_used&~dyn->insts[ninst].n.xmmh_unneeded;
uint16_t xmms_needed = dyn->insts[ninst].n.xmms_used&~dyn->insts[ninst].n.xmms_unneeded;
// an unresolved exit (float barrier or jump out of the block) can reach code
// that reads the full registers, so pin every lane live there, upper-64/96 included
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) || (dyn->insts[ninst].x64.jmp && (dyn->insts[ninst].x64.jmp_insts==-1)))
{
if(dyn->use_xmm) xmm_needed = 0xffff;
if(dyn->use_ymm) ymm_needed = 0xffff;
if(dyn->use_xmm) xmmh_needed = 0xffff;
if(dyn->use_xmm) xmms_needed = 0xffff;
}
if(xmm_needed || ymm_needed)
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed);
if(xmm_needed || ymm_needed || xmmh_needed || xmms_needed)
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed, xmmh_needed, xmms_needed);
}
// then proagate the unneeded one: those which are not needed (not used anymore and will be overwritten)
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded) {
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.xmmh_unneeded || dyn->insts[ninst].n.xmms_unneeded) {
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded, dyn->insts[ninst].n.xmmh_unneeded, dyn->insts[ninst].n.xmms_unneeded);
}
}
// try to add some preload of XYMM on jump were it would make sense
@@ -1493,6 +1514,11 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
}
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a)
{
dyn->n.xmm_used |= 1<<a;
}
// AVX helpers
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
{
@@ -1552,12 +1578,17 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
if(i2 && !dyn->insts[i2-1].x64.has_next) // need a previous opcode to set the preload, unless it's the #0
return;
// check if there is jump out or outside this loop
int has_host_call = 0;
for(int i=i2; i<ninst; ++i) {
if(!dyn->insts[i].x64.has_next || (dyn->insts[i].x64.barrier&BARRIER_FLOAT))
return;
// for now, unneeded stop at first jump, so this should also stop there
if(dyn->insts[i].x64.jmp/* && ((dyn->insts[i].x64.jmp_insts>ninst) || (dyn->insts[i].x64.jmp_insts<i2))*/)
return;
if(dyn->insts[i].host_call_clobber)
return;
if(dyn->insts[i].host_call)
has_host_call = 1;
}
uint16_t ymm_mask = 0;
for(int i=0; i<16; ++i) {
@@ -1596,9 +1627,9 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
}
}
preload = (preload&0xffff) | (ymm_mask<<16); // update ymm_mask
//TODO: should check native calls too?
dyn->insts[i2].preload_xmmymm = preload;
dyn->insts[i2].preload_from = ninst;
dyn->insts[i2].preload_host_call = has_host_call;
dyn->insts[i2].n.xmm_unneeded |= preload&0xffff;
dyn->insts[i2].n.ymm_unneeded |= ymm_mask;
}
+4 -4
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
#define __DYNAREC_ARM_FUNCTIONS_H__
@@ -70,10 +71,6 @@ void neoncacheUnwind(neoncache_t* cache);
void fpu_save_and_unwind(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
const char* getCacheName(int t, int n);
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex);
@@ -96,6 +93,9 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached);
// add a preload of SSE/AVX register preload before i2, for a jump in ninst. Might not do it if there is jump in between that goes outside this ninst-i2 interval
void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload);
// mark a SSE reg as read by the current opcode, without touching its cache entry
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a);
// AVX helpers
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg);
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg);
+118 -80
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -34,6 +35,12 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
int lock = l?((l==LOCK_LOCK)?1:2):0;
if(lock==2) *l = 0;
if(dyn->insts[ninst].use_lrcpc) {
if(!unscaled) {
NOLRCPC();
} else { absmax = 0; mask=0;}
} // there is no "Scaled" version, only Unscaled
if(rex.is32bits && rex.is67)
return geted16(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, rex, s);
@@ -43,7 +50,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
uint8_t scratch = x2;
*fixaddress = 0;
if(hint>0) ret = hint;
if(hint>0 && hint<xRAX) scratch = hint;
if(hint>0 && !IS_GPR(hint)) scratch = hint;
int absmin = 0;
if(s) absmin=-absmax;
int seg_done = 0;
@@ -197,7 +204,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
}
ADDy_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
} else {
PASS3(int tmp = TO_NAT(sib & 0x07) + (rex.b << 3));
PASS3(int tmp = TO_NAT((sib & 0x07) + (rex.b << 3)));
if(sub) {
SUBy_REG(ret, tmp, scratch);
} else {
@@ -220,8 +227,9 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
ret = hint;
}
if(rex.seg && !seg_done) {
scratch = (hint>0 && !IS_GPR(hint)) ? hint : x2;
if(scratch==ret)
scratch=ret+1;
scratch = xLR; // dead between opcodes, ret+1 can be a guest register
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
//seg offset is 64bits, so no truncation here
ADDx_REGy(hint, scratch, ret);
@@ -259,7 +267,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
case 1: offset = F8S; break;
case 2: offset = F16S; break;
}
if(offset && (offset>=absmax && offset<=absmin && !(offset&mask))) {
if(offset && (offset>=absmin && offset<=absmax && !(offset&mask))) {
*fixaddress = offset;
offset = 0;
}
@@ -313,7 +321,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
if(rex.seg) {
if(scratch==ret)
scratch=ret+1;
scratch = xLR;
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
//seg offset is 64bits, so no truncation here
if(IS_GPR(ret)) {
@@ -342,8 +350,10 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
TABLE64C(x2, const_epilog);
SMEND();
CHECK_DFNONE(0);
if(dyn->have_purge)
#ifndef BOX64EC // no CALLRET on Box64EC yet
if (BOX64DRENV(dynarec_callret) >= 3)
doLeaveBlock(dyn, ninst, x4, x5, x6);
#endif
BR(x2);
}
@@ -418,18 +428,22 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
if(reg!=x1) {
MOVx_REG(x1, xRIP);
}
if(dyn->have_purge && !dyn->insts[ninst].x64.has_callret)
#ifndef BOX64EC // no CALLRET on Box64EC yet
if(BOX64DRENV(dynarec_callret) >= 3 && !dyn->insts[ninst].x64.has_callret)
doLeaveBlock(dyn, ninst, x4, x5, x6);
#ifdef HAVE_TRACE
//MOVx(x3, 15); no access to PC reg
BLR(dest); // save LR...
#else
#endif
// #ifdef HAVE_TRACE
// The BLR form is only for gdb backtraces, but it breaks the
// return-address-stack prediction on every block-to-block jump, which is
// not worth it. Uncomment temporarily when debugging with gdb.
// BLR(dest); // save LR...
// #else
if (dyn->insts[ninst].x64.has_callret) {
BLR(dest); // save LR...
} else {
BR(dest);
}
#endif
// #endif
}
void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
@@ -438,21 +452,21 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
CHECK_DFNONE(0);
MOVz_REG(x1, xRIP);
SMEND();
#ifndef BOX64EC // no CALLRET on Box64EC yet
if(BOX64DRENV(dynarec_callret)) {
// pop the actual return address for ARM stack
LDPx_S7_postindex(xLR, x6, xSP, 16);
SUBx_REG(x6, x6, xRIP); // is it the right address?
if(dyn->have_purge)
if (BOX64DRENV(dynarec_callret) >= 3)
doLeaveBlock(dyn, ninst, x4, x5, x3);
CBNZx(x6, 2*4);
RET(xLR);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
SUBx_U12(xSP, xSavedSP, 16);
}
#endif
NOTEST(x2);
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
if(dyn->have_purge && !BOX64DRENV(dynarec_callret))
doLeaveBlock(dyn, ninst, x4, x5, x6);
#ifdef HAVE_TRACE
BLR(dest);
#else
@@ -541,6 +555,7 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
{
MAYUSE(fnc);
dyn->insts[ninst].host_call = 1;
CHECK_DFNONE(1);
#if STEP == 0
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
@@ -557,10 +572,16 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
#ifdef BOX64EC
// R10 and R11 are not preserved by the C call in the EC map
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10]));
#endif
fpu_pushcache(dyn, ninst, savereg, 0);
for(int i=0; i<dyn->n.fpu_scratch; ++i)
VSTR128_S9_preindex(SCRATCH0+i, xSP, -16);
}
#ifdef _WIN32
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
#endif
TABLE64C(reg, fnc);
BLR(reg);
@@ -568,6 +589,8 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
MOVx_REG(ret, xEmu);
}
if(ret!=-2) {
for(int i=dyn->n.fpu_scratch-1; i>=0; --i)
VLDR128_S9_postindex(SCRATCH0+i, xSP, 16);
LDPx_S7_postindex(xEmu, savereg, xSP, 16);
#define GO(A, B) if(ret==x##A) { \
LDRx_U12(x##B, xEmu, offsetof(x64emu_t, regs[_##B])); \
@@ -581,21 +604,30 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
GO(RSP, RBP);
GO(RSI, RDI);
GO(R8, R9);
#ifdef BOX64EC
GO(R10, R11);
#endif
#undef GO
fpu_popcache(dyn, ninst, savereg, 0); // savereg will not be used
}
if(saveflags) {
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
}
#ifdef BOX64EC
// x87pc is x5, the pop above restored an argument: reload it
NATIVE_RESTORE_X87PC();
#else
if(savereg!=x87pc && dyn->need_x87check) {
NATIVE_RESTORE_X87PC();
}
#endif
//SET_NODF();
}
void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1, int arg2, int sav1, int sav2)
{
MAYUSE(fnc);
dyn->insts[ninst].host_call = 1;
CHECK_DFNONE(1);
#if STEP == 0
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
@@ -609,11 +641,14 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
#ifdef BOX64EC
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10])); // not preserved by the C call, as in call_c
#endif
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
fpu_pushcache(dyn, ninst, x87pc, 0);
#ifdef _WIN32
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
#endif
if(arg1!=-1)
FMOVD(0, arg1);
@@ -633,6 +668,9 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
GO(RSP, RBP);
GO(RSI, RDI);
GO(R8, R9);
#ifdef BOX64EC
GO(R10, R11);
#endif
#undef GO
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
fpu_popcache(dyn, ninst, x1, 0); // savereg will not be used
@@ -642,6 +680,8 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
{
MAYUSE(fnc);
dyn->insts[ninst].host_call = 1;
dyn->insts[ninst].host_call_clobber = 1;
CHECK_DFNONE(1);
#if STEP == 0
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
@@ -1162,6 +1202,11 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
for (int i=0; (i<8) && (ret==-1); ++i)
if(dyn->n.x87cache[i]==-1)
ret = i;
if(ret==-1) {
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
dyn->abort = 1;
return -1;
}
// found, setup and grab the value
dyn->n.x87cache[ret] = st;
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
@@ -1290,6 +1335,11 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
for (int i=0; (i<8) && (ret==-1); ++i)
if(dyn->n.x87cache[i]==-1)
ret = i;
if(ret==-1) {
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
dyn->abort = 1;
return;
}
// found, setup and grab the value
dyn->n.x87cache[ret] = st;
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
@@ -1443,7 +1493,7 @@ static int isx87Empty(dynarec_arm_t* dyn)
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
{
dyn->insts[ninst].mmx_used = 1;
if(!dyn->n.x87stack && isx87Empty(dyn))
if(dyn->n.x87stack || !isx87Empty(dyn))
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
if(dyn->n.mmxcache[a]!=-1)
return dyn->n.mmxcache[a];
@@ -1456,7 +1506,7 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
{
dyn->insts[ninst].mmx_used = 1;
if(!dyn->n.x87stack && isx87Empty(dyn))
if(dyn->n.x87stack || !isx87Empty(dyn))
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
if(dyn->n.mmxcache[a]!=-1)
return dyn->n.mmxcache[a];
@@ -1527,8 +1577,9 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
dyn->n.xmm_used |= 1<<a;
return dyn->n.ssecache[a].reg;
}
if(!(dyn->n.xmm_used&(1<<a)))
dyn->n.xmm_unneeded |= 1<<a;
dyn->n.xmm_used |= 1<<a;
dyn->n.xmm_unneeded |= 1<<a;
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
dyn->n.ssecache[a].write = 1; // it will be write...
return dyn->n.ssecache[a].reg;
@@ -1537,10 +1588,13 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
{
dyn->n.xmm_used |= 1<<a;
if(dyn->n.ssecache[a].v==-1)
return;
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
dyn->n.ymm_used |= 1<<a;
if(dyn->n.ssecache[a].v!=-1) {
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
}
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
dyn->n.ssecache[a].v = -1;
}
// YMM part too
if(is_avx_zero_unset(dyn, ninst, a)) {
@@ -1558,9 +1612,6 @@ void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
fpu_free_reg(dyn, i);
}
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
dyn->n.ssecache[a].v = -1;
return;
}
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)
@@ -1632,7 +1683,7 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
if(!next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
dyn->n.neoncache[i].v = 0;
if(next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
dyn->n.xmm_used |= (1<<dyn->n.neoncache[i].n);
dyn->n.ymm_used |= (1<<dyn->n.neoncache[i].n);
}
// All done
if(old!=-1) {
@@ -1640,36 +1691,6 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
}
}
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
{
for (int i=0; i<16; ++i) {
if(dyn->n.ssecache[i].v!=-1) {
dyn->n.xmm_used |= 1<<i;
if(dyn->n.ssecache[i].write) {
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
}
}
}
//AVX
if(dyn->ymm_zero) {
int s1_set = 0;
for(int i=0; i<16; ++i)
if(is_avx_zero(dyn, ninst, i)) {
if(!s1_set) {
ADDx_U12(s1, xEmu, offsetof(x64emu_t, ymm[0]));
s1_set = 1;
}
STPx_S7_offset(xZR, xZR, s1, i*16);
}
}
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->n.neoncache[i].t == NEON_CACHE_YMMW) || (dyn->n.neoncache[i].t == NEON_CACHE_YMMR))
dyn->n.xmm_used |= 1<<dyn->n.neoncache[i].n;
}
}
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
{
dyn->n.xmm_used |= 1<<a;
@@ -2134,19 +2155,23 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
int i2 = dyn->insts[ninst].x64.jmp_insts;
if(i2<0)
return;
MESSAGE(LOG_DUMP, "\tCache Transform ---- ninst=%d -> %d\n", ninst, i2);
MESSAGE(LOG_DUMP, "\tFPU Cache Transform ---- ninst=%d -> %d\n", ninst, i2);
uint32_t unneeded = dyn->insts[i2].n.xmm_unneeded | (dyn->insts[i2].n.ymm_unneeded<<16);
if((!i2) || (dyn->insts[i2].x64.barrier&BARRIER_FLOAT)) {
if(dyn->insts[i2].preload_host_call)
unneeded &= ~dyn->insts[i2].preload_xmmymm;
int need_purge = 0;
if(dyn->n.stack_next)
need_purge = 1;
for(int i=0; i<24 && !need_purge; ++i)
for(int i=0; i<32 && !need_purge; ++i)
if(dyn->n.neoncache[i].v)
need_purge = 1;
if(dyn->ymm_zero)
need_purge = 1;
if(need_purge) { // there is something at ninst for i
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
}
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
return;
}
neoncache_t cache_i2 = dyn->insts[i2].n;
@@ -2173,7 +2198,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
purge = 0;
if(purge) {
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
return;
}
}
@@ -2248,8 +2273,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
cache.neoncache[i].t = NEON_CACHE_ST_I64;
} else if(cache.neoncache[i].t == NEON_CACHE_ST_F && cache_i2.neoncache[i].t == NEON_CACHE_ST_I64) {
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
VFCVTZSQS(i, i);
cache.neoncache[i].t = NEON_CACHE_ST_D;
FCVT_D_S(i, i);
VFCVTZSQD(i, i);
cache.neoncache[i].t = NEON_CACHE_ST_I64;
} else if(cache.neoncache[i].t == NEON_CACHE_ST_I64 && cache_i2.neoncache[i].t == NEON_CACHE_ST_F) {
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
SCVTFDD(i, i);
@@ -2277,9 +2303,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
}
}
}
if(stack_cnt != cache_i2.stack) {
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
int a = stack_cnt - cache_i2.stack;
if(stack_cnt != cache_i2.stack || dyn->n.x87stack != cache_i2.x87stack) {
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d / pending %d -> %d -\n", stack_cnt, cache_i2.stack, dyn->n.x87stack, cache_i2.x87stack);
int a = dyn->n.x87stack - cache_i2.x87stack;
// Add x87stack to emu fpu_stack
LDRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
if(a>0) {
@@ -2353,12 +2379,25 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
j64 = (GETMARKF2)-(dyn->native_size);
CBZw(x1, j64);
}
if(dyn->insts[ninst].need_nat_flags)
if(dyn->insts[ninst].need_nat_flags) {
#ifdef BOX64EC
// updateflags uses x1 to x5 and x6 is guest R9: NZCV goes through the emu
MRS_nzcv(x1);
STRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
#else
MRS_nzcv(x6);
#endif
}
TABLE64C(x1, const_updateflags_arm64);
BLR(x1);
if(dyn->insts[ninst].need_nat_flags)
if(dyn->insts[ninst].need_nat_flags) {
#ifdef BOX64EC
LDRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
MSR_nzcv(x1);
#else
MSR_nzcv(x6);
#endif
}
MARKF2;
}
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
@@ -2445,7 +2484,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
EORx_mask(s2, s2, 1, 35, 0); //mask=1<<NZCV_C
}
}
#undef GL_MRS
#undef GO_MRS
if(mrs) MSR_nzcv(s2);
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
@@ -2465,7 +2504,6 @@ static void flush_native_flags(dynarec_arm_t* dyn, int ninst, int s1, uint8_t fl
{
// 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);
@@ -2496,7 +2534,6 @@ 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 || (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].nat_flags_in; //flags before the opcode
@@ -2820,7 +2857,8 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
}
#endif
printf_log(LOG_NONE, "BOX64 Dynarec: Error, unable to free a reg for YMM %d at inst=%d on pass %d\n", ymm, ninst, STEP);
return i;
dyn->abort = 1;
return SCRATCH0;
}
// Get an XMM quad reg and preload it (or do nothing if not possible)
@@ -2885,10 +2923,6 @@ void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
STLXRw(s3, s2, s1);
CBNZw(s3, -3*4);
}
// set tick
LDRx_U12(s2, xEmu, offsetof(x64emu_t, context));
LDRw_U12(s2, s2, offsetof(box64context_t, tick));
STRw_U12(s2, s1, offsetof(dynablock_t, tick)-offsetof(dynablock_t, in_used));
MESSAGE(LOG_INFO, "-------- doEnter\n");
}
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
@@ -2988,8 +3022,8 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
// grab the dynablock address in x5, as this on will not be erased by crc functions
int delta = -(dyn->native_size + sizeof(void*));
LDRx_literal(x5, delta);
// move away xEMU to X6, should be safe there
MOVx_REG(x6, xEmu);
// move away xEMU to the stack, x6 is guest R9 on Box64EC
STPx_S7_preindex(xEmu, xZR, xSP, -16);
// prepare and call the crc function
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
@@ -2997,10 +3031,14 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
BLR(x3);
// done, move away result and restore xEmu
MOVw_REG(x1, xEmu);
MOVx_REG(xEmu, x6);
LDPx_S7_postindex(xEmu, xZR, xSP, 16);
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
SUBw_REG(x1, x1, x2);
CBZw(x1, 4+2*4);
TABLE64C(x3, const_native_next_invalidate);
BLR(x3);
#ifdef BOX64EC
// x5 held the dynablock, which is x87pc here
NATIVE_RESTORE_X87PC();
#endif
}
+108 -61
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNAREC_ARM64_HELPER_H__
#define __DYNAREC_ARM64_HELPER_H__
@@ -39,6 +40,9 @@
#ifndef FEMIT
#define FEMIT(A) EMIT(A)
#endif
#ifndef LEMIT
#define LEMIT(A) EMIT(A)
#endif
#ifndef ENDPREFIX
#define ENDPREFIX
#endif
@@ -83,7 +87,7 @@
}
#define GETEDw(D) \
if (MODREG) { \
ed = xEAX + (nextop & 7) + (rex.b << 3); \
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
wback = 0; \
} else { \
SMREAD(); \
@@ -132,7 +136,7 @@
#define WBACKx if(wback) {STx(ed, wback, fixedaddress); SMWRITE();}
// Write back ed in wback (if wback not 0)
#define WBACKw if(wback) {STW(ed, wback, fixedaddress); SMWRITE();}
//FAKEELike GETED, but doesn't get anything
//FAKEED like GETED, but doesn't get anything
#define FAKEED \
if (MODREG) { \
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
@@ -167,7 +171,7 @@
ed = i; \
wb1 = 1; \
}
//Compute wback for MDREG only, no fetching
//Compute wback for MODREG only, no fetching
#define CALCEW() \
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
//GETEW will use i for ed, and can use r3 for wback.
@@ -184,20 +188,6 @@
ed = i; \
wb1 = 1; \
}
//GETEW will use i for ed, and can use r3 for wback.
#define GETEW32(i, D) \
if (MODREG) { \
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
UXTHw(i, wback); \
ed = i; \
wb1 = 0; \
} else { \
SMREAD(); \
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff << 1, (1 << 1) - 1, rex, NULL, 0, D); \
LDH(i, wback, fixedaddress); \
ed = i; \
wb1 = 1; \
}
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
#define GETSEW(i, D) \
if (MODREG) { \
@@ -270,27 +260,6 @@
wb1 = 1; \
ed = i; \
}
//GETEB will use i for ed, and can use r3 for wback.
#define GETEB32(i, D) \
if (MODREG) { \
if (rex.rex) { \
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
wb2 = 0; \
} else { \
wback = (nextop & 7); \
wb2 = (wback >> 2) * 8; \
wback = TO_NAT(wback & 3); \
} \
UBFXx(i, wback, wb2, 8); \
wb1 = 0; \
ed = i; \
} else { \
SMREAD(); \
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
LDB(i, wback, fixedaddress); \
wb1 = 1; \
ed = i; \
}
// Write eb (ed) back to original register / memory
#define EBBACK if(wb1) {STB(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
// no fetch version of GETGB
@@ -334,6 +303,14 @@
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
// Get GX as a quad (might use x1)
// mark an XMM reg as accessed scalar-only (upper-64 untouched) in this opcode
#define MARK_XMM_SCALAR(a) dyn->n.xmm_scalar |= (1 << (a))
// test if the upper-64 of an XMM reg is proven dead in this opcode
#define XMMH_UNNEEDED(a) (dyn->insts[ninst].n.xmmh_unneeded & (1 << (a)))
// mark an XMM reg as accessed scalar-single (only low-32 touched, upper-96 untouched)
#define MARK_XMM_SCALAR_SINGLE(a) ((dyn->n.xmm_scalar |= (1 << (a))), (dyn->n.xmm_scalar_single |= (1 << (a))))
// test if the upper-96 of an XMM reg is proven dead in this opcode
#define XMMS_UNNEEDED(a) (dyn->insts[ninst].n.xmms_unneeded & (1 << (a)))
#define GETGX(a, w) \
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
@@ -498,7 +475,7 @@
a = fpu_get_scratch(dyn, ninst); \
VLDR128_U12(a, ed, fixedaddress); \
}
// Get EX as a quad, (x3 is used)
// Get EX as a quad but don't load anything, just reserve an empty reg (x3 is used)
#define GETEX_empty_Y(a, D) \
if(MODREG) { \
a = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3)); \
@@ -589,7 +566,7 @@
SMWRITE2(); \
}
#define YMM0(a) ymm_mark_zero(dyn, ninst, a);
#define YMM0(a) ymm_mark_zero(dyn, ninst, a)
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
@@ -601,15 +578,15 @@
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || BOX64ENV(dynarec_aligned_atomics))
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || BOX64ENV(dynarec_aligned_atomics))
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
// CALL will use xLR for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL(F, ret) call_c(dyn, ninst, F, x87pc, ret, 1, 0)
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
#define CALL(F, ret) call_c(dyn, ninst, F, xLR, ret, 1, 0)
// CALL_ will use xLR for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x87pc, ret, 1, reg)
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, xLR, ret, 1, reg)
// CALL_S will use xLR for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
#define CALL_S(F, ret) call_c(dyn, ninst, F, x87pc, ret, 0, 0)
#define CALL_S(F, ret) call_c(dyn, ninst, F, xLR, ret, 0, 0)
// CALL_D will use x7 for the call address. Use for function having 1 or 2 double args and returning 1 double
// All regs are saved, including xmm0-7, will move arg1/arg2 to D0, D1, return D0 to ret (unless any is -1)
#define CALL_D(F, ret, arg1, arg2, sav1, sav2) call_d(dyn, ninst, F, ret, arg1, arg2, sav1, sav2)
@@ -627,6 +604,26 @@
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
#define GETMARKSEG dyn->insts[ninst].markseg
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
#ifdef BOX64EC
// x6 is guest R9 and x87pc is x5, so keep the flags in the emu across the retry loop
#define MARKLOCK_SAVE_FLAGS() do { \
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
MRS_nzcv(x4); \
STRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
MARKLOCK; \
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
LDRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
MSR_nzcv(x4); \
} while (0)
#else
#define MARKLOCK_SAVE_FLAGS() do { \
MOVx_REG(x6, xFlags); \
MRS_nzcv(x87pc); \
MARKLOCK; \
MOVx_REG(xFlags, x6); \
MSR_nzcv(x87pc); \
} while (0)
#endif
#define GETMARKLOCK dyn->insts[ninst].marklock
// Branch to MARK if cond (use j64)
@@ -700,7 +697,7 @@
#define B_MARK3(cond) \
j64 = GETMARK3-(dyn->native_size); \
Bcond(cond, j64)
// Test bit N of A and branch to MARK3 if not set
// Test bit N of A and branch to MARK2 if not set
#define TBZ_MARK2(A, N) \
j64 = GETMARK2-(dyn->native_size); \
TBZ(A, N, j64)
@@ -880,6 +877,56 @@
}
#endif
#ifndef X87_ARITH_NAN_START_D
#define X87_ARITH_NAN_START_D(va, vb, tmp) \
FMAXD(tmp, va, vb); \
FCMEQD(tmp, tmp, tmp)
#endif
#ifndef X87_ARITH_NAN_END_D
#define X87_ARITH_NAN_END_D(vres, vb, tmp, tmp2) \
FCMEQD(tmp2, vres, vres); \
VBIC(tmp2, tmp, tmp2); \
VSHLQ_64(tmp2, tmp2, 63); \
VORR(vres, vres, tmp2); \
VSSHRQ_64(tmp2, vres, 63); \
FCMEQD(tmp, vres, vres); \
VMVNQ(tmp, tmp); \
VANDQ(tmp, tmp, tmp2); \
VSSHRQ_64(tmp2, vb, 63); \
VMVNQ(tmp2, tmp2); \
VANDQ(tmp, tmp, tmp2); \
FCMEQD(tmp2, vb, vb); \
VMVNQ(tmp2, tmp2); \
VANDQ(tmp, tmp, tmp2); \
VBIT(vres, vb, tmp)
#endif
#ifndef X87_ARITH_NAN_START_S
#define X87_ARITH_NAN_START_S(va, vb, tmp) \
FMAXS(tmp, va, vb); \
FCMEQS(tmp, tmp, tmp)
#endif
#ifndef X87_ARITH_NAN_END_S
#define X87_ARITH_NAN_END_S(vres, vb, tmp, tmp2) \
FCMEQS(tmp2, vres, vres); \
VBIC(tmp2, tmp, tmp2); \
VSHL_32(tmp2, tmp2, 31); \
VORR(vres, vres, tmp2); \
VSSHR_32(tmp2, vres, 31); \
FCMEQS(tmp, vres, vres); \
VMVNQ(tmp, tmp); \
VANDQ(tmp, tmp, tmp2); \
VSSHR_32(tmp2, vb, 31); \
VMVNQ(tmp2, tmp2); \
VANDQ(tmp, tmp, tmp2); \
FCMEQS(tmp2, vb, vb); \
VMVNQ(tmp2, tmp2); \
VANDQ(tmp, tmp, tmp2); \
VBIT(vres, vb, tmp)
#endif
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
#define STP_REGS(A, B) STPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
#define LDP_REGS(A, B) LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
@@ -1002,8 +1049,8 @@
#define READFLAGS(A) \
if((A)!=X_PEND \
&& (dyn->f==status_unk)) { \
TABLE64C(x6, const_updateflags_arm64); \
BLR(x6); \
TABLE64C(x5, const_updateflags_arm64); \
BLR(x5); \
dyn->f = status_none; \
} else if((A)==X_ALL) flushNative(dyn, ninst);
#endif
@@ -1011,8 +1058,8 @@
#define GRABFLAGS(A) \
if((A)!=X_PEND \
&& ((dyn->f==status_unk) || (dyn->f==status_set))) { \
TABLE64C(x6, const_updateflags_arm64); \
BLR(x6); \
TABLE64C(x5, const_updateflags_arm64); \
BLR(x5); \
dyn->f = status_none; \
}
@@ -1079,7 +1126,7 @@
#undef PREFLAGSNEEDED
#define PREFLAGSNEEDED() \
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
if(dyn->always_test && ninst && (ninst && dyn->insts[ninst-1].x64.has_callret)) \
checkCRC(dyn, ninst);
#if STEP < 2
@@ -1301,7 +1348,7 @@
#define x87_get_cache STEPNAME(x87_get_cache)
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
#define x87_get_st STEPNAME(x87_get_st)
#define x87_get_st_empty STEPNAME(x87_get_st)
#define x87_get_st_empty STEPNAME(x87_get_st_empty)
#define x87_free STEPNAME(x87_free)
#define x87_forget STEPNAME(x87_forget)
#define x87_reget_st STEPNAME(x87_reget_st)
@@ -1369,12 +1416,12 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
@@ -1456,8 +1503,8 @@ void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4);
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include "arm64_emitter.h"
+19 -5
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define INIT uintptr_t sav_addr=addr
#define FINI \
@@ -7,14 +8,18 @@
#define MESSAGE(A, ...) do {} while (0)
#define READFLAGS(A) \
do { \
dyn->insts[ninst].x64.use_flags = A; if(dyn->f!=status_none_pending) dyn->f = status_none;\
if(!BOX64ENV(dynarec_df) && (A)&X_PEND) dyn->insts[ninst].x64.use_flags = X_ALL; \
dyn->f = status_none
dyn->f = status_none; \
} while(0)
#define SETFLAGS(A,B) \
do { \
dyn->insts[ninst].x64.set_flags = A; \
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?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); }}
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); }} \
} while(0)
#define EMIT(A) dyn->native_size+=4
#define JUMP(A, C) \
do { \
@@ -33,7 +38,11 @@
dyn->n.combined1 = dyn->n.combined2 = 0;\
dyn->n.swapped = 0; dyn->n.barrier = 0; \
dyn->insts[ninst].f_entry = dyn->f; \
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
dyn->insts[ninst].host_call = 0; \
dyn->insts[ninst].host_call_clobber = 0;\
dyn->insts[ninst].x64.strongmem = ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem)); \
if(dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat) dyn->insts[ninst].use_lrcpc = 1; \
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
AREFLAGSNEEDED()
#define INST_EPILOG \
@@ -41,7 +50,11 @@
dyn->insts[ninst].n = dyn->n; \
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && !dyn->insts[ninst].set_nat_flags) \
dyn->insts[ninst].nat_flags_op=NAT_FLAG_OP_UNUSABLE; \
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
dyn->insts[ninst].x64.has_next = (ok>0)?1:0; \
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
dyn->insts[ninst].use_lrcpc = 0; \
if(dyn->insts[ninst].x64.strongmem && dyn->insts[ninst].use_lrcpc) dyn->insts[ninst].x64.strongmem = 0
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
@@ -53,7 +66,8 @@
}
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
#define FEMIT(A) do {dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE; EMIT(A);} while(0)
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} while(0)
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
#define UFLAG_IF if(dyn->insts[ninst].x64.set_flags)
+8 -2
View File
@@ -1,14 +1,18 @@
// SPDX-License-Identifier: MIT
#define INIT
#define FINI
#define MESSAGE(A, ...) do {} while (0)
#define EMIT(A) do {} while (0)
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} 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) \
do { \
dyn->insts[ninst].x64.set_flags = A; \
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
if(((B)&SF_SET_PENDING)!=SF_SET_PENDING) dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):((dyn->f==status_none)?status_none:status_none_pending); \
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; }
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; } \
} while(0)
#define NEW_INST \
dyn->insts[ninst].f_entry = dyn->f; \
dyn->n.combined1 = dyn->n.combined2 = 0;\
@@ -17,7 +21,9 @@
#define INST_EPILOG \
dyn->insts[ninst].n = dyn->n; \
dyn->insts[ninst].f_exit = dyn->f
dyn->insts[ninst].f_exit = dyn->f; \
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
dyn->insts[ninst].use_lrcpc = 0
#define INST_NAME(name)
+1 -3
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define INIT dyn->native_size = 0
#define FINI \
if(ninst) { \
@@ -32,9 +33,6 @@
} while(0)
#define FTABLE64(A, V) do { mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); } while(0)
#define CALLRET_RET(A) do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); dyn->insts[ninst+1].sep=1; ++dyn->sep_size; \
} \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
} \
+1 -9
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#define INIT
#define FINI \
if(ninst) \
@@ -45,15 +46,6 @@
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0)
#define CALLRET_RET(A) \
do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
MESSAGE(LOG_DUMP, " Dynablock*\n"); \
dyn->block += sizeof(void*); \
dyn->native_size+=sizeof(void*); \
dyn->insts[ninst].size2 += sizeof(void*); \
dyn->sep[dyn->sep_size].x64_offs = addr - dyn->start; \
dyn->sep[dyn->sep_size].nat_offs = dyn->native_size; \
++dyn->sep_size; \
} \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; \
dyn->callrets[dyn->callret_size++].offs = dyn->native_size; \
+15 -5
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNAREC_ARM_PRIVATE_H_
#define __DYNAREC_ARM_PRIVATE_H_
@@ -50,7 +51,6 @@ typedef union sse_cache_s {
};
} sse_cache_t;
typedef struct callret_s callret_t;
typedef struct sep_s sep_t;
typedef struct neoncache_s {
// Neon cache
@@ -86,6 +86,14 @@ typedef struct neoncache_s {
uint16_t ymm_needed; // 1bit for ymmXX were value is needed
uint16_t xmm_unneeded; // 1bit for xmmXX were value is not needed
uint16_t ymm_unneeded; // 1bit for ymmXX were value is not needed
uint16_t xmmh_used; // [127:64] of low-128 used (scalar-vs-packed liveness)
uint16_t xmmh_needed; // 1bit if XMM upper-64 needed
uint16_t xmmh_unneeded; // 1bit if XMM upper-64 not needed
uint16_t xmms_used; // [127:32] of low-128 used (scalar-single-vs-wider liveness)
uint16_t xmms_needed; // 1bit if XMM upper-96 needed
uint16_t xmms_unneeded; // 1bit if XMM upper-96 not needed
uint16_t xmm_scalar; // regs accessed scalar-only (upper-64 untouched) this op
uint16_t xmm_scalar_single; // regs accessed scalar-single-only (upper-96 untouched) this op
uint64_t ymm_regs; // 4bits (0-15) position of 16 ymmXX regs removed
} neoncache_t;
@@ -127,7 +135,6 @@ typedef struct instruction_arm64_s {
uint8_t last_write:1; // [strongmem] the last write in a SEQ
uint8_t lock:1; // [strongmem] lock semantic
uint8_t wfe:1; // opcode uses sevl + wfe
uint8_t sep:1; // opcode is a secondary entry point
uint8_t set_nat_flags; // 0 or combinaison of native flags define
uint8_t use_nat_flags; // 0 or combinaison of native flags define
uint8_t use_nat_flags_before; // 0 or combinaison of native flags define
@@ -149,6 +156,11 @@ typedef struct instruction_arm64_s {
unsigned x87_used:1; // no fine tracking, just a global "any reg used"
unsigned fpu_used:1; // any xmm/ymm/x87/mmx reg used
unsigned fpupurge:1; // this opcode will purge all fpu regs
unsigned host_call:1; // this opcode performs a native call
unsigned host_call_clobber:1; // native call does not preserve cached xmm0-7 (call_n)
unsigned preload_host_call:1; // preload range contains a host call, needs write-back at merge
unsigned use_lrcpc:1;// use the various lrcpc opcode here instead of regular LD/ST + memory barrier
unsigned has_lrcpc:1;// set if the opcode has some lrcpc opcode in it
flagcache_t f_exit; // flags status at end of instruction
neoncache_t n; // neoncache at end of instruction (but before poping)
flagcache_t f_entry; // flags status before the instruction begin
@@ -182,14 +194,13 @@ typedef struct dynarec_arm_s {
int* jmps; // variable array of jump instructions
int jmp_sz;
int jmp_cap;
int peeking_flags;
int* predecessor;// single array of all predecessor
dynablock_t* dynablock;
instsize_t* instsize;
size_t insts_size; // size of the instruction size array (calculated)
int callret_size; // size of the array
int sep_size; // size of the array
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
sep_t* sep; // array of secondary entry point
uintptr_t forward; // address of the last end of code while testing forward
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
int32_t forward_size; // size at the forward point
@@ -204,7 +215,6 @@ typedef struct dynarec_arm_s {
uint8_t use_mmx:1;
uint8_t use_xmm:1;
uint8_t use_ymm:1;
uint8_t have_purge:1; // set to 1 if block can be purged
uint8_t is_file_mapped:1; // if the memory is a mapped file (probably binary, not a memory)
void* gdbjit_block;
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
+1 -1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -45,7 +46,6 @@ void* create_updateflags()
// pass 0
updateflags_pass0(&helper, jmp_df);
// check if all flags are handled
helper.have_purge = 0; // force no purge
int ok = 1;
for(int i=d_none; i<d_unknown; ++i)
if(!jmp_df[i]) {
+63 -46
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -164,7 +165,7 @@ SETMARK(d_inc64);
RET(xLR);
SETMARK(d_imul8);
LDRSH_U12(x1, xEmu, offsetof(x64emu_t, res));
ASRxw(x2, x1, 7);
ASRw(x2, x1, 7);
CMPSw_REG_ASR(x2, x1, 16);
CSETw(x3, cNE);
BFIw(xFlags, x3, F_CF, 1);
@@ -499,24 +500,24 @@ SETMARK(d_cmp64);
SETMARK(d_tst8);
LDRB_U12(x1, xEmu, offsetof(x64emu_t, res));
MOV32w(x2, 0xff);
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
emit_test8(dyn, ninst, x1, x2, x3, x4);
RET(xLR);
SETMARK(d_tst16);
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
MOV32w(x2, 0xffff);
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
emit_test16(dyn, ninst, x1, x2, x3, x4);
RET(xLR);
SETMARK(d_tst32);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
MOV32w(x2, 0xffffffff);
rex.w = 0;
emit_test32(dyn, ninst, rex, x1, x2, x3, x4, x5);
emit_test32(dyn, ninst, rex, x1, x2, x3, x4);
RET(xLR);
SETMARK(d_tst64);
LDRx_U12(x1, xEmu, offsetof(x64emu_t, res));
MOV64x(x2, 0xffffffffffffffffULL);
rex.w = 1;
emit_test32(dyn, ninst, rex, x1, x2, x3, x4, x5);
emit_test32(dyn, ninst, rex, x1, x2, x3, x4);
rex.w = 0;
RET(xLR);
// for ADC & SBB, the emit_adcX cannot be used because the CF state is not saved
@@ -822,8 +823,8 @@ SETMARK(d_rol64);
BFIw(xFlags, x2, F_OF, 1);
} else {
LDRx_U12(x2, xEmu, offsetof(x64emu_t, op1));
LSRw_IMM(x3, x2, 62);
EORw_REG_LSR(x3, x3, x3, 1);
LSRx(x3, x2, 62);
EORx_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
}
BFXILw(xFlags, x1, 0, 1);
@@ -831,7 +832,7 @@ SETMARK(d_rol64);
SETMARK(d_ror8);
LDRB_U12(x1, xEmu, offsetof(x64emu_t, res));
if(BOX64ENV(cputype)) {
LSLw_IMM(x2, x1, 6);
LSRw(x2, x1, 6);
EORw_REG_LSR(x3, x2, x2, 1);
BFIw(xFlags, x3, F_OF, 1);
} else {
@@ -844,7 +845,7 @@ SETMARK(d_ror8);
SETMARK(d_ror16);
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
if(BOX64ENV(cputype)) {
LSLw_IMM(x2, x1, 14);
LSRw(x2, x1, 14);
EORw_REG_LSR(x3, x2, x2, 1);
BFIw(xFlags, x3, F_OF, 1);
} else {
@@ -857,7 +858,7 @@ SETMARK(d_ror16);
SETMARK(d_ror32);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
if(BOX64ENV(cputype)) {
LSLw_IMM(x2, x1, 30);
LSRw(x2, x1, 30);
EORw_REG_LSR(x3, x2, x2, 1);
BFIw(xFlags, x3, F_OF, 1);
} else {
@@ -870,8 +871,8 @@ SETMARK(d_ror32);
SETMARK(d_ror64);
LDRx_U12(x1, xEmu, offsetof(x64emu_t, res));
if(BOX64ENV(cputype)) {
LSLx_IMM(x2, x1, 62);
EORw_REG_LSR(x3, x2, x2, 1);
LSRx(x2, x1, 62);
EORx_REG_LSR(x3, x2, x2, 1);
BFIw(xFlags, x3, F_OF, 1);
} else {
LDRx_U12(x2, xEmu, offsetof(x64emu_t, op1));
@@ -883,30 +884,33 @@ SETMARK(d_ror64);
SETMARK(d_shrd16);
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
LDRH_U12(x3, xEmu, offsetof(x64emu_t, op2));
if(BOX64ENV(cputype)) {
LSRw(x4, x1, 14);
EORw_REG_LSR(x4, x4, x4, 1);
BFIw(xFlags, x4, F_OF, 1);
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
} else {
ANDw_mask(x4, x3, 0, 3); // mask = 0x0f
SUBw_U12(x4, x4, 16);
NEGw_REG(x4, x4);
LSRw_REG(x4, x1, x4);
EORw_REG_LSR(x4, x4, x2, 15);
BFIw(xFlags, x4, F_OF, 1);
BFCw(xFlags, F_AF, 1);
}
CBNZw(x3, 4+4);
LDRw_U12(x3, xEmu, offsetof(x64emu_t, op2));
ANDw_mask(x4, x3, 0, 4); // count = op2 & 0x1f
CBNZw(x4, 4+4);
RET(xLR);
SUBw_U12(x4, x3, 1);
LSRw_REG(x4, x2, x4);
LSRw(x5, x3, 16); // fill = op2 >> 16
if(BOX64ENV(cputype)) {
CMPSw_U12(x3, 15);
CSELw(x4, x4, xZR, cGT);
LSRw(x3, x1, 14);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
SUBw_U12(x3, x4, 1);
LSRw_REG(x3, x2, x3);
CMPSw_U12(x4, 16);
CSELw(x3, xZR, x3, cGT);
BFIw(xFlags, x3, F_CF, 1);
} else {
EORw_REG_LSR(x3, x5, x2, 15);
BFIw(xFlags, x3, F_OF, 1);
BFCw(xFlags, F_AF, 1);
CMPSw_U12(x4, 16);
SUBw_U12(x3, x4, 1);
LSRw_REG(x3, x2, x3); // dest >> (count-1)
SUBw_U12(x4, x4, 17);
LSRw_REG(x5, x5, x4); // fill >> (count-17)
CSELw(x3, x5, x3, cGT);
BFIw(xFlags, x3, F_CF, 1);
}
BFIw(xFlags, x4, F_CF, 1);
LSRw(x4, x1, 15);
BFIw(xFlags, x4, F_SF, 1);
TSTw_mask(x1, 0, 15);
@@ -975,24 +979,37 @@ SETMARK(d_shrd64);
SETMARK(d_shld16);
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
LDRH_U12(x3, xEmu, offsetof(x64emu_t, op2));
CBNZw(x3, 4+4);
LDRw_U12(x3, xEmu, offsetof(x64emu_t, op2));
ANDw_mask(x4, x3, 0, 4); // count = op2 & 0x1f
CBNZw(x4, 4+4);
RET(xLR);
SUBw_U12(x4, x3, 16);
NEGw_REG(x4, x4);
LSRw_REG(x4, x2, x4);
BFIw(xFlags, x4, F_CF, 1);
LSRw(x5, x3, 16); // fill = op2 >> 16
if(BOX64ENV(cputype)) {
EORw_REG_LSR(x4, xFlags, x1, 15);
CMPSw_U12(x3, 15);
CSELw(x4, x4, xFlags, cGT);
BFIw(xFlags, x4, F_OF, 1);
MOV32w(x3, 16);
SUBw_REG(x3, x3, x4);
LSRw_REG(x3, x2, x3); // dest >> (16-count)
CMPSw_U12(x4, 16);
CSELw(x3, xZR, x3, cGT);
BFIw(xFlags, x3, F_CF, 1);
EORw_REG_LSR(x3, xFlags, x1, 15);
CMPSw_U12(x4, 15);
CSELw(x3, xFlags, x3, cGT);
BFIw(xFlags, x3, F_OF, 1);
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
} else {
LSRw(x4, x2, 14);
EORw_REG_LSR(x4, x4, x4, 1);
BFIw(xFlags, x4, F_OF, 1);
LSRw(x3, x2, 14);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
BFCw(xFlags, F_AF, 1);
CMPSw_U12(x4, 16);
MOV32w(x3, 16);
SUBw_REG(x3, x3, x4);
LSRw_REG(x3, x2, x3); // dest >> (16-count)
MOV32w(x2, 32);
SUBw_REG(x2, x2, x4);
LSRw_REG(x5, x5, x2); // fill >> (32-count)
CSELw(x3, x5, x3, cGT);
BFIw(xFlags, x3, F_CF, 1);
}
LSRw(x4, x1, 15);
BFIw(xFlags, x4, F_SF, 1);
+169 -44
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
@@ -26,16 +27,54 @@
#include "khash.h"
#include "rbtree.h"
// ---- fast hash for block change detection ----
static uint32_t normal_fast_hash(void* p, uint32_t len)
{
const uint8_t* data = (const uint8_t*)p;
uint64_t h = len * UINT64_C(0x9E3779B97F4A7C15);
while (len >= 8) {
uint64_t k;
__builtin_memcpy(&k, data, 8);
k *= UINT64_C(0xBF58476D1CE4E5B9);
k ^= k >> 31;
h ^= k;
h *= UINT64_C(0x94D049BB133111EB);
data += 8;
len -= 8;
}
if (len) {
uint64_t k = 0;
switch(len) {
case 7: k |= (uint64_t)data[6] << 48; /* fall through */
case 6: k |= (uint64_t)data[5] << 40; /* fall through */
case 5: k |= (uint64_t)data[4] << 32; /* fall through */
case 4: k |= (uint64_t)data[3] << 24; /* fall through */
case 3: k |= (uint64_t)data[2] << 16; /* fall through */
case 2: k |= (uint64_t)data[1] << 8; /* fall through */
case 1: k |= (uint64_t)data[0];
}
k *= UINT64_C(0xBF58476D1CE4E5B9);
k ^= k >> 31;
h ^= k;
h *= UINT64_C(0x94D049BB133111EB);
}
h ^= h >> 33;
h *= UINT64_C(0xFF51AFD7ED558CCD);
h ^= h >> 33;
return (uint32_t)h;
}
uint32_t X31_hash_code(void* addr, int len)
{
if(!len) return 0;
#ifdef ARCH_CRC
ARCH_CRC(addr, len);
#endif
uint8_t* p = (uint8_t*)addr;
int32_t h = *p;
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
return (uint32_t)h;
return normal_fast_hash(addr, (uint32_t)len);
}
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
@@ -46,9 +85,6 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
// remove jumptable without waiting
setJumpTableDefault64(db->x64_addr);
for(int i=0; i<db->sep_size; ++i)
if(db->sep[i].active)
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
db->done = 0;
@@ -75,24 +111,104 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
return db;
}
static void DeferFreeDynablockMap(dynablock_t* db)
static void QueueZombieDynablock(dynablock_t* db);
static void RetireOrphanDynablocks(void)
{
for (int i = 0; i < my_context->db_orphan_count; ) {
dynablock_t* db = my_context->db_orphan[i];
if (db && native_lock_get_d(&db->in_used) > 0) {
++i;
continue;
}
my_context->db_orphan[i] = my_context->db_orphan[--my_context->db_orphan_count];
// released by its last user: requeue it instead of freeing right away, a thread
// may still be running the last instructions of the block (and the enter/leave
// pair is not atomic with the code around it)
if (db) QueueZombieDynablock(db);
}
}
static void QueueOrphanDynablock(dynablock_t* db)
{
if (my_context->db_orphan_count == my_context->db_orphan_size) {
int nsize = my_context->db_orphan_size ? my_context->db_orphan_size * 2 : 64;
dynablock_t** nlist = box_malloc(nsize * sizeof(dynablock_t*));
if (!nlist) return;
if (my_context->db_orphan_count)
memcpy(nlist, my_context->db_orphan, my_context->db_orphan_count * sizeof(dynablock_t*));
if (my_context->db_orphan) box_free(my_context->db_orphan);
my_context->db_orphan = nlist;
my_context->db_orphan_size = nsize;
}
my_context->db_orphan[my_context->db_orphan_count++] = db;
}
static void QueueZombieDynablock(dynablock_t* db)
{
// enq for a deferred free so any threads still running in this block has a better chance to finish.
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
if(my_context->db_zombie[my_context->db_zombie_head])
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
// Queue full: free the oldest queued block that no running dynarec chain holds (in_used), compact the queue.
int idx = -1; // queue position of the entry to drop, 0 = oldest
int idx_in_used = 0; // in_used count of that entry
for (int i = 0; i < DB_ZOMBIE_SIZE; ++i) {
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
dynablock_t* z = my_context->db_zombie[slot];
if (!z)
continue;
int cnt = native_lock_get_d(&z->in_used);
if (cnt <= 0) {
idx = i;
idx_in_used = cnt;
break;
}
if (idx < 0) {
idx = i; // remember the oldest held block, in case all of them are held
idx_in_used = cnt;
}
}
if (idx < 0)
idx = 0; // queue is full of empty slots: just drop the oldest one
// free the picked entry
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + idx + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
if (idx_in_used > 0) {
printf_log(LOG_DEBUG, "Warning, all %d queued dynablocks are still in use, deferring the oldest one (in_used=%d)\n", DB_ZOMBIE_SIZE, idx_in_used);
QueueOrphanDynablock(my_context->db_zombie[slot]);
} else if (my_context->db_zombie[slot])
FreeDynarecMap((uintptr_t)my_context->db_zombie[slot]->actual_block);
// shift all newer entries over the dropped one, then queue db at the tail
for (int i = idx; i < DB_ZOMBIE_SIZE - 1; ++i) {
int cur = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
int nxt = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
my_context->db_zombie[cur] = my_context->db_zombie[nxt];
}
my_context->db_zombie[(my_context->db_zombie_head - 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE] = db;
} else {
my_context->db_zombie[my_context->db_zombie_head] = db;
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
my_context->db_zombie_count++;
}
my_context->db_zombie[my_context->db_zombie_head] = db;
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
}
static void DeferFreeDynablockMap(dynablock_t* db)
{
if (my_context->db_orphan_count) RetireOrphanDynablocks();
QueueZombieDynablock(db);
}
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;
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;
if(my_context->db_zombie[idx] && ((void*)my_context->db_zombie[idx]>=addr) && ((void*)my_context->db_zombie[idx]<(addr+sz)))
my_context->db_zombie[idx] = NULL;
}
for(int i=0; i<my_context->db_orphan_count; )
if(my_context->db_orphan[i] && ((void*)my_context->db_orphan[i]>=addr) && ((void*)my_context->db_orphan[i]<(addr+sz)))
my_context->db_orphan[i] = my_context->db_orphan[--my_context->db_orphan_count];
else
++i;
}
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
@@ -127,9 +243,6 @@ void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
// remove jumptable without waiting
if(need_remove) {
setJumpTableDefault64(db->x64_addr);
for(int i=0; i<db->sep_size; ++i)
if(db->sep[i].active)
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
}
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
@@ -154,9 +267,6 @@ void MarkDynablock(dynablock_t* db)
{
if(db) {
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
for(int i=0; i<db->sep_size; ++i)
if(db->sep[i].active)
setJumpTableIfRef64(db->x64_addr+db->sep[i].x64_offs, db->jmpnext, db->block+db->sep[i].nat_offs);
if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
dynablock_t* old = db;
db = getDB((uintptr_t)old->x64_addr);
@@ -225,8 +335,10 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
void dynablock_leave_runtime(dynablock_t* db)
{
if(!db) return;
if(!db->tick) return;
#ifdef HAVE_IN_USED
if(BOX64ENV(dynarec_callret) < 3) return;
__atomic_fetch_sub(&db->in_used, 1, __ATOMIC_ACQ_REL);
#endif
}
dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
@@ -273,12 +385,15 @@ 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
*/
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, dynablock_t* block)
{
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)))
return NULL;
dynablock_t* block = getDB(addr);
if(!block)
block = getDB(addr);
if(block==SEARCHED_NO_DYNABLOCK)
block = NULL;
if(block && block->to_delete) {
// just delete the block then, so we can create a new one right away
FreeDynablock(block, 1, 1);
@@ -352,14 +467,6 @@ dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int n
block->done = 1; // don't validate the block if the size is null, but keep the block
rb_inc(my_context->db_sizes, block->x64_size, block->x64_size+1);
}
for(int i=0; i<block->sep_size; ++i) {
uintptr_t x64_offs = block->sep[i].x64_offs;
uintptr_t nat_offs = block->sep[i].nat_offs;
if(addJumpTableIfDefault64(block->x64_addr+x64_offs, (block->dirty || block->always_test)?block->jmpnext:(block->block+nat_offs)))
block->sep[i].active = 1;
else
block->sep[i].active = 0;
}
}
}
if(need_lock)
@@ -374,11 +481,21 @@ dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int n
void FlushZombieDynablocks(void)
{
if (!my_context) return;
if (my_context->db_orphan_count) {
for (int i = 0; i < my_context->db_orphan_count; ++i)
if (my_context->db_orphan[i] && native_lock_get_d(&my_context->db_orphan[i]->in_used) <= 0)
FreeDynarecMap((uintptr_t)my_context->db_orphan[i]->actual_block);
box_free(my_context->db_orphan);
my_context->db_orphan = NULL;
my_context->db_orphan_size = 0;
my_context->db_orphan_count = 0;
}
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);
if (my_context->db_zombie[idx] && native_lock_get_d(&my_context->db_zombie[idx]->in_used) <= 0)
FreeDynarecMap((uintptr_t)my_context->db_zombie[idx]->actual_block);
}
my_context->db_zombie_count = 0;
}
@@ -386,9 +503,26 @@ void FlushZombieDynablocks(void)
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
{
int is_inhotpage = isInHotPage(addr);
dynablock_t* db = NULL;
if(!is_inhotpage && !BOX64ENV(dynarec_dirty)) {
db = getDB(addr);
if(db && db->x64_size) {
uintptr_t dbstart = (uintptr_t)db->x64_addr;
uintptr_t dbend = dbstart + db->x64_size;
for(uintptr_t page = (dbstart&~(X86_PAGE_SIZE-1)); page < dbend; page += X86_PAGE_SIZE) {
if(page == (addr&~(X86_PAGE_SIZE-1))) continue; // skip the first page
if(checkInHotPage(page)) {
is_inhotpage = 1;
break;
}
}
}
if(!db)
db = SEARCHED_NO_DYNABLOCK;
}
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
return NULL;
dynablock_t *db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1);
db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1, db);
if(db && db->done && db->block && getNeedTest(addr)) {
//if (db->always_test) SchedYield(); // just calm down...
uint32_t hash = X31_hash_code((void*)db->x64_readaddr, db->x64_size);
@@ -403,7 +537,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
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);
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0, SEARCHED_NO_DYNABLOCK);
} else {
if(is_inhotpage) {
db->always_test = 2;
@@ -427,15 +561,6 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
}
#endif
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
if(!db->always_test)
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(setJumpTableIfRef64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs), db->jmpnext))
db->sep[i].active = 1;
else
db->sep[i].active = 0;
}
}
}
}
+1 -9
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNABLOCK_PRIVATE_H_
#define __DYNABLOCK_PRIVATE_H_
@@ -11,17 +12,10 @@ typedef struct callret_s {
uint32_t type:1;
} callret_t;
typedef struct sep_s {
uint32_t active:1;
uint32_t nat_offs:31;
uint32_t x64_offs;
} sep_t;
typedef struct dynablock_s {
void* block; // block-sizeof(void*) == self
void* actual_block; // the actual start of the block (so block-sizeof(void*))
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;
uintptr_t x64_size;
size_t native_size;
@@ -39,11 +33,9 @@ typedef struct dynablock_s {
int callret_size; // size of the array
int isize;
int arch_size; // size of of arch dependant infos
int sep_size; // SEP are the Secondary Entry Point
instsize_t* instsize;
void* arch; // arch dependant per inst info (can be NULL)
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
sep_t* sep; // secondary entry point, offsets are relative to x64_addr & block
void* jmpnext; // a branch jmpnext code when block is marked
size_t table64size;// to check table64
void* table64; // to relocate the table64
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include <string.h>
+1
View File
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef __DYNACACHE_RELOC_H__
#define __DYNACACHE_RELOC_H__
Loaded 100 of 2342 files, more files were not shown because too many files have changed in this diff. Show more