mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-10 14:07:25 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 196d474e6d | |||
| f839b95843 | |||
| dc3a5b331a |
@@ -19,7 +19,6 @@ log.txt
|
|||||||
# Generated source files
|
# Generated source files
|
||||||
src/common/scm_rev.cpp
|
src/common/scm_rev.cpp
|
||||||
dist/english_plurals/generated_en.ts
|
dist/english_plurals/generated_en.ts
|
||||||
*-toolchain.cmake
|
|
||||||
|
|
||||||
# Project/editor files
|
# Project/editor files
|
||||||
*.swp
|
*.swp
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
set(CROSS_TARGET "powerpc64le" CACHE STRING "Cross-compilation target (aarch64, powerpc64le, riscv64, etc)")
|
|
||||||
|
|
||||||
set(CMAKE_SYSROOT /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-gcc)
|
|
||||||
set(CMAKE_CXX_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-g++)
|
|
||||||
|
|
||||||
# search programs in the host environment
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
||||||
|
|
||||||
# search headers and libraries in the target environment
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
|
||||||
+1
-137
@@ -2,122 +2,7 @@
|
|||||||
|
|
||||||
General guide for cross compiling.
|
General guide for cross compiling.
|
||||||
|
|
||||||
## Gentoo
|
## Debian ARM64
|
||||||
|
|
||||||
Gentoo's cross-compilation setup is relatively easy, provided you're already familiar with portage.
|
|
||||||
|
|
||||||
### Crossdev
|
|
||||||
|
|
||||||
First, emerge crossdev via `sudo emerge -a sys-devel/crossdev`.
|
|
||||||
|
|
||||||
Now, set up the environment depending on the target architecture; e.g.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo crossdev powerpc64le
|
|
||||||
sudo crossdev aarch64
|
|
||||||
```
|
|
||||||
|
|
||||||
### QEMU
|
|
||||||
|
|
||||||
Installing a qemu user setup is recommended for testing. To do so, you will need the relevant USE flags:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
app-emulation/qemu static-user qemu_user_targets_ppc64le qemu_user_targets_aarch64
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that to use cross-emerged libraries, you will need to tell qemu where the sysroot is. You can do this with an alias:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
alias qemu-ppc64le="qemu-ppc64le -L /usr/powerpc64le-unknown-linux-gnu"
|
|
||||||
alias qemu-aarch64="qemu-aarch64 -L /usr/aarch64-unknown-linux-gnu"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
Some packages have broken USE flags on other architectures; you'll also need to set up python targets. In `/usr/<target>-unknown-linux-gnu/etc/portage/package.use`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
>=net-misc/curl-8.16.0-r1 ssl
|
|
||||||
|
|
||||||
*/* PYTHON_TARGETS: python3_13 PYTHON_SINGLE_TARGET: python3_13
|
|
||||||
*/* pam
|
|
||||||
|
|
||||||
sys-apps/util-linux pam su
|
|
||||||
app-shells/bash -readline
|
|
||||||
>=dev-libs/libpcre2-10.47 unicode
|
|
||||||
>=x11-libs/libxkbcommon-1.12.3 X
|
|
||||||
>=sys-libs/zlib-1.3.1-r1 minizip
|
|
||||||
>=app-alternatives/gpg-1-r3 ssl
|
|
||||||
>=app-crypt/gnupg-2.5.13-r2 ssl
|
|
||||||
|
|
||||||
dev-libs/* -introspection
|
|
||||||
media-libs/harfbuzz -introspection
|
|
||||||
dev-libs/quazip -qt5 qt6
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependencies should be about the same [as normal Gentoo](./Deps.md), but removing gamemode and renderdoc is recommended. Keep in mind that when emerging, you want to use `emerge-<target>-unknown-linux-gnu`, e.g. `emerge-powerpc64le-unknown-linux-gnu`.
|
|
||||||
|
|
||||||
Enable GURU in the cross environment (as root):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
mkdir -p /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf
|
|
||||||
cat << EOF > /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf/guru.conf
|
|
||||||
[guru]
|
|
||||||
location = /var/db/repos/guru
|
|
||||||
auto-sync = no
|
|
||||||
priority = 1
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Now emerge your dependencies:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo emerge-powerpc64le-unknown-linux-gnu -aU app-arch/lz4 app-arch/zstd app-arch/unzip \
|
|
||||||
dev-libs/libfmt dev-libs/libusb dev-libs/mcl dev-libs/sirit dev-libs/oaknut \
|
|
||||||
dev-libs/unordered_dense dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \
|
|
||||||
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
|
||||||
dev-util/vulkan-utility-libraries dev-util/glslang \
|
|
||||||
media-libs/libva media-libs/opus media-video/ffmpeg \
|
|
||||||
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
|
|
||||||
net-libs/enet net-libs/mbedtls \
|
|
||||||
sys-libs/zlib \
|
|
||||||
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt dev-cpp/catch \
|
|
||||||
net-wireless/wireless-tools \
|
|
||||||
dev-qt/qtbase:6 dev-libs/quazip \
|
|
||||||
virtual/pkgconfig
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
A toolchain is provided in `CMakeModules/GentooCross.cmake`. To use it:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF
|
|
||||||
```
|
|
||||||
|
|
||||||
Now build as normal:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake --build build/ppc64 -j$(nproc)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alternatively
|
|
||||||
|
|
||||||
Only emerge the absolute necessities:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo emerge-powerpc64le-unknown-linux-gnu -aU media-video/ffmpeg media-libs/libsdl2 dev-qt/qtbase:6
|
|
||||||
```
|
|
||||||
|
|
||||||
Then set `YUZU_USE_CPM=ON`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF -DYUZU_USE_CPM=ON
|
|
||||||
```
|
|
||||||
|
|
||||||
## ARM64
|
|
||||||
|
|
||||||
### Debian ARM64
|
|
||||||
|
|
||||||
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
||||||
|
|
||||||
@@ -203,24 +88,3 @@ And finally, run the compiled executable with QEMU!
|
|||||||
```sh
|
```sh
|
||||||
qemu-aarch64 build/aarch64/bin/eden
|
qemu-aarch64 build/aarch64/bin/eden
|
||||||
```
|
```
|
||||||
|
|
||||||
## PowerPC
|
|
||||||
|
|
||||||
This is a guide for FreeBSD users mainly.
|
|
||||||
|
|
||||||
Now you got a PowerPC sysroot - quickly decompress it somewhere, say `/home/user/opt/powerpc64le`. Create a toolchain file, for example `powerpc64le-toolchain.cmake`; always [consult the manual](https://man.freebsd.org/cgi/man.cgi?query=cmake-toolchains&sektion=7&manpath=FreeBSD+13.2-RELEASE+and+Ports).
|
|
||||||
|
|
||||||
There is a script to automatically do all of this under `./tools/setup-cross-sysroot.sh`.
|
|
||||||
|
|
||||||
Remember to add `-mabi=elfv1` to `CFLAGS`/`CXXFLAGS` otherwise the program will crash.
|
|
||||||
|
|
||||||
Specify:
|
|
||||||
|
|
||||||
- `YUZU_USE_CPM`: Set this to `ON` so packages can be found and built if your sysroot doesn't have them.
|
|
||||||
- `YUZU_USE_EXTERNAL_FFMPEG`: Set this to `ON` as well.
|
|
||||||
|
|
||||||
Then run using a program such as QEMU to emulate userland syscalls:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake --build build-ppc64-pc-freebsd -t dynarmic_tests -- -j8 && qemu-ppc64-static -L $HOME/opt/ppc64-freebsd/sysroot ./build-ppc64-pc-freebsd/bin/dynarmic_tests
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# PowerPC 64 backend
|
|
||||||
|
|
||||||
The ppc64 backend currently only supports the little endian variant, with big endian support being experimental for the time being. Additionally only A32 is supported (for now).
|
|
||||||
|
|
||||||
- Flag handling: Flags are emulated via software, while there may be some funny tricks with the CTR, I'd rather not bother - plus it's widely known that those instructions are not nice on real metal - so I would rather take the i-cache cost.
|
|
||||||
- 128-bit atomics: No 128-bit atomic support is provided, this may cause wrong or erroneous execution in some contexts.
|
|
||||||
|
|
||||||
To handle endianess differences all 16/32/64-bit loads and stores to the "emulated memory" are byteswapped beforehand.
|
|
||||||
@@ -7,12 +7,11 @@ A dynamic recompiler for ARM.
|
|||||||
|
|
||||||
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
||||||
|
|
||||||
The only supported host architectures are x86-64, PowerPC 64, and AArch64. There are no plans to support any 32-bit architectures.
|
The only supported host architectures are x86-64, and AArch64. There are no plans to support any 32-bit architectures.
|
||||||
|
|
||||||
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
||||||
|
|
||||||
Design documentation can be found at [./Design.md](./Design.md).
|
Design documentation can be found at [./Design.md](./Design.md).
|
||||||
PowerPC design documentation can be found at [./PowerPC](./PowerPC.md).
|
|
||||||
|
|
||||||
Alternatives to Dynarmic
|
Alternatives to Dynarmic
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
Vendored
-5
@@ -249,11 +249,6 @@ endif()
|
|||||||
# TZDB (Time Zone Database)
|
# TZDB (Time Zone Database)
|
||||||
add_subdirectory(nx_tzdb)
|
add_subdirectory(nx_tzdb)
|
||||||
|
|
||||||
# PowerPC emitter
|
|
||||||
if (ARCHITECTURE_powerpc64)
|
|
||||||
add_subdirectory(powah)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(tz tz/tz/tz.cpp)
|
add_library(tz tz/tz/tz.cpp)
|
||||||
target_include_directories(tz PUBLIC ./tz)
|
target_include_directories(tz PUBLIC ./tz)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -166,7 +166,7 @@ detect_architecture_symbols(
|
|||||||
"_M_MRX000")
|
"_M_MRX000")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH powerpc64
|
ARCH ppc64
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc64__"
|
"__ppc64__"
|
||||||
"__powerpc64__"
|
"__powerpc64__"
|
||||||
@@ -174,7 +174,7 @@ detect_architecture_symbols(
|
|||||||
"_M_PPC64")
|
"_M_PPC64")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH powerpc
|
ARCH ppc
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc__"
|
"__ppc__"
|
||||||
"__ppc"
|
"__ppc"
|
||||||
|
|||||||
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
add_library(powah INTERFACE)
|
|
||||||
target_include_directories(powah INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
target_compile_options(powah INTERFACE -Wno-unused-parameter)
|
|
||||||
|
|
||||||
add_executable(powah_tests tests.cpp)
|
|
||||||
create_target_directory_groups(powah_tests)
|
|
||||||
target_link_libraries(powah_tests PRIVATE Catch2::Catch2WithMain)
|
|
||||||
Vendored
-145
@@ -1,145 +0,0 @@
|
|||||||
vabsdub,VX,04,1027
|
|
||||||
vabsduh,VX,04,1091
|
|
||||||
vabsduw,VX,04,1155
|
|
||||||
vaddcuw,VX,04,384
|
|
||||||
vaddfp,VX,04,10
|
|
||||||
vaddsbs,VX,04,768
|
|
||||||
vaddshs,VX,04,832
|
|
||||||
vaddsws,VX,04,896
|
|
||||||
vaddubm,VX,04,0
|
|
||||||
vaddubs,VX,04,512
|
|
||||||
vadduhm,VX,04,64
|
|
||||||
vadduhs,VX,04,576
|
|
||||||
vadduwm,VX,04,128
|
|
||||||
vadduws,VX,04,640
|
|
||||||
vand,VX,04,1028
|
|
||||||
vandc,VX,04,1092
|
|
||||||
vavgsb,VX,04,1282
|
|
||||||
vavgsh,VX,04,1346
|
|
||||||
vavgsw,VX,04,1410
|
|
||||||
vavgub,VX,04,1026
|
|
||||||
vavguh,VX,04,1090
|
|
||||||
vavguw,VX,04,1154
|
|
||||||
vcfsx,VDU,04842
|
|
||||||
vcfux,VDU,04778
|
|
||||||
vcmpbfp,VXR,04,966
|
|
||||||
vcmpeqfp,VXR,04,198
|
|
||||||
vcmpequb,VXR,04,6
|
|
||||||
vcmpequh,VXR,04,70
|
|
||||||
vcmpequw,VXR,04,134
|
|
||||||
vcmpgefp,VXR,04,454
|
|
||||||
vcmpgtfp,VXR,04,710
|
|
||||||
vcmpgtsb,VXR,04,774
|
|
||||||
vcmpgtsh,VXR,04,838
|
|
||||||
vcmpgtsw,VXR,04,902
|
|
||||||
vcmpgtub,VXR,04,518
|
|
||||||
vcmpgtuh,VXR,04,582
|
|
||||||
vcmpgtuw,VXR,04,646
|
|
||||||
vctsxs,VDU,04970
|
|
||||||
vctuxs,VDU,04906
|
|
||||||
vexptefp,VY,04,394
|
|
||||||
vlogefp,VY,04,458
|
|
||||||
vmaddfp,VXC,46
|
|
||||||
vmaxfp,VX,04,1034
|
|
||||||
vmaxsb,VX,04,258
|
|
||||||
vmaxsh,VX,04,322
|
|
||||||
vmaxsw,VX,04,386
|
|
||||||
vmaxub,VX,04,2
|
|
||||||
vmaxuh,VX,04,66
|
|
||||||
vmaxuw,VX,04,130
|
|
||||||
vmhaddshs,VXC,32
|
|
||||||
vmhraddshs,VXC,33
|
|
||||||
vminfp,VX,04,1098
|
|
||||||
vminsb,VX,04,770
|
|
||||||
vminsh,VX,04,834
|
|
||||||
vminsw,VX,04,898
|
|
||||||
vminub,VX,04,514
|
|
||||||
vminuh,VX,04,578
|
|
||||||
vminuw,VX,04,642
|
|
||||||
vmladduhm,VXC,34
|
|
||||||
vmrghb,VX,04,12
|
|
||||||
vmrghh,VX,04,76
|
|
||||||
vmrghw,VX,04,140
|
|
||||||
vmrglb,VX,04,268
|
|
||||||
vmrglh,VX,04,332
|
|
||||||
vmrglw,VX,04,396
|
|
||||||
vmsummbm,VXC,37
|
|
||||||
vmsumshm,VXC,40
|
|
||||||
vmsumshs,VXC,41
|
|
||||||
vmsumubm,VXC,36
|
|
||||||
vmsumuhm,VXC,38
|
|
||||||
vmsumuhs,VXC,39
|
|
||||||
vmulesb,VX,04,776
|
|
||||||
vmulesh,VX,04,840
|
|
||||||
vmuleub,VX,04,520
|
|
||||||
vmuleuh,VX,04,584
|
|
||||||
vmulosb,VX,04,264
|
|
||||||
vmulosh,VX,04,328
|
|
||||||
vmuloub,VX,04,8
|
|
||||||
vmulouh,VX,04,72
|
|
||||||
vnmsubfp,VXC,47
|
|
||||||
vnor,VX,04,1284
|
|
||||||
vor,VX,04,1156
|
|
||||||
vperm,VXC,43
|
|
||||||
vpkpx,VX,04,782
|
|
||||||
vpkshss,VX,04,398
|
|
||||||
vpkshus,VX,04,270
|
|
||||||
vpkswss,VX,04,462
|
|
||||||
vpkswus,VX,04,334
|
|
||||||
vpkuhum,VX,04,14
|
|
||||||
vpkuhus,VX,04,142
|
|
||||||
vpkuwum,VX,04,78
|
|
||||||
vpkuwus,VX,04,206
|
|
||||||
vrefp,VY,04,266
|
|
||||||
vrfim,VY,04,714
|
|
||||||
vrfin,VY,04,522
|
|
||||||
vrfip,VY,04,650
|
|
||||||
vrfiz,VY,04,586
|
|
||||||
vrlb,VX,04,4
|
|
||||||
vrlh,VX,04,68
|
|
||||||
vrlw,VX,04,132
|
|
||||||
vrsqrtefp,VY,04,330
|
|
||||||
vsel,VXC,42
|
|
||||||
vsl,VX,04,452
|
|
||||||
vslb,VX,04,260
|
|
||||||
vsldoi,VX,04,/ SH 44
|
|
||||||
vslh,VX,04,324
|
|
||||||
vslo,VX,04,1036
|
|
||||||
vslw,VX,04,388
|
|
||||||
vspltb,VU,04,524
|
|
||||||
vsplth,VU,04,588
|
|
||||||
vspltisb,VS,04,780
|
|
||||||
vspltish,VS,04,844
|
|
||||||
vspltisw,VS,04,908
|
|
||||||
vspltw,VSU,04,652
|
|
||||||
vsr,VX,04,708
|
|
||||||
vsrab,VX,04,772
|
|
||||||
vsrah,VX,04,836
|
|
||||||
vsraw,VX,04,900
|
|
||||||
vsrb,VX,04,516
|
|
||||||
vsrh,VX,04,580
|
|
||||||
vsro,VX,04,1100
|
|
||||||
vsrw,VX,04,644
|
|
||||||
vsubcuw,VX,04,1408
|
|
||||||
vsubfp,VX,04,74
|
|
||||||
vsubsbs,VX,04,1792
|
|
||||||
vsubshs,VX,04,1856
|
|
||||||
vsubsws,VX,04,1920
|
|
||||||
vsububm,VX,04,1024
|
|
||||||
vsububs,VX,04,1536
|
|
||||||
vsubuhm,VX,04,1088
|
|
||||||
vsubuhs,VX,04,1600
|
|
||||||
vsubuwm,VX,04,1152
|
|
||||||
vsubuws,VX,04,1664
|
|
||||||
vsumsws,VX,04,1928
|
|
||||||
vsum2sws,VX,04,1672
|
|
||||||
vsum4sbs,VX,04,1800
|
|
||||||
vsum4shs,VX,04,1608
|
|
||||||
vsum4ubs,VX,04,1544
|
|
||||||
vupkhpx,VY,04,846
|
|
||||||
vupkhsb,VY,04,526
|
|
||||||
vupkhsh,VY,04,590
|
|
||||||
vupklpx,VY,04,974
|
|
||||||
vupklsb,VY,04,654
|
|
||||||
vupklsh,VY,04,718
|
|
||||||
vxor,VX,04,122
|
|
||||||
Vendored
-6
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
$CC data2code.c -o data2code && ./data2code data.txt >powah_gen_base.hpp
|
|
||||||
$CC --target=powerpc64le test.S -c -o test && objdump -SC test
|
|
||||||
Vendored
-222
@@ -1,222 +0,0 @@
|
|||||||
add[o][.],Add,XO,31,266
|
|
||||||
addc[o][.],Add Carrying,XO,31,10
|
|
||||||
adde[o][.],Add Extended,XO,31,138
|
|
||||||
addi,Add Immediate,D,14,
|
|
||||||
addic,Add Immediate Carrying,D,12,
|
|
||||||
addic.,Add Immediate Carrying and Record,D,13,
|
|
||||||
addis,Add Immediate Shifted,D,15,
|
|
||||||
addme[o][.],Add to Minus One Extended,XO,31,234
|
|
||||||
addze[o][.],Add to Zero Extended,XO,31,202
|
|
||||||
and[.],AND,X,31,28
|
|
||||||
andc[.],AND with Complement,X,31,60
|
|
||||||
andi.,AND Immediate,D,28,
|
|
||||||
andis.,AND Immediate Shifted,D,29,
|
|
||||||
b[l][a],Branch,I,18,
|
|
||||||
bc[l][a],Branch Conditional,B,16,
|
|
||||||
bcctr[l],Branch Conditional to Count Register,XL,19,528
|
|
||||||
bclr[l],Branch Conditional Link Register,XL,19,16
|
|
||||||
cmp,Compare,X,31,0
|
|
||||||
cmpi,Compare Immediate,D,11,
|
|
||||||
cmpl,Compare Logical,X,31,32
|
|
||||||
cmpli,Compare Logical Immediate,D,10,
|
|
||||||
cntlzd,Count Leading Zeros Doubleword,X,31,58
|
|
||||||
cntlzw[.],Count Leading Zeros Word,X,31,26
|
|
||||||
crand,Condition Register AND,XL,19,257
|
|
||||||
crandc,Condition Register AND with Complement,XL,19,129
|
|
||||||
creqv,Condition Register Equivalent,XL,19,289
|
|
||||||
crnand,Condition Register NAND,XL,19,225
|
|
||||||
crnor,Condition Register NOR,XL,19,33
|
|
||||||
cror,Condition Register OR,XL,19,449
|
|
||||||
crorc,Condition Register OR with Complement,XL,19,417
|
|
||||||
crxor,Condition Register XOR,XL,19,193
|
|
||||||
dcbf,Data Cache Block Flush,X,31,86
|
|
||||||
dcbi,Data Cache Block Invalidate,X,31,470
|
|
||||||
dcbst,Data Cache Block Store,X,31,54
|
|
||||||
dcbt,Data Cache Block Touch,X,31,278
|
|
||||||
dcbtst,Data Cache Block Touch for Store,X,31,246
|
|
||||||
dcbz,Data Cache Block Set to Zero,X,31,1014
|
|
||||||
divd,Divide Doubleword,XO,31,489
|
|
||||||
divdu,Divide Doubleword Unsigned,XO,31,457
|
|
||||||
divw[o][.],Divide Word,XO,31,491
|
|
||||||
divwu[o][.],Divide Word Unsigned,XO,31,459
|
|
||||||
eciwx,External Control in Word Indexed (opt.),X,31,310
|
|
||||||
ecowx,External Control out Word Indexed (opt.),X,31,438
|
|
||||||
eieio,Enforce In-order Execution of I/O,X,31,854
|
|
||||||
eqv[.],Equivalent,X,31,284
|
|
||||||
extsb[.],Extend Sign Byte,X,31,954
|
|
||||||
extsh[.],Extend Sign Halfword,XO,31,922
|
|
||||||
extsw,Extend Sign Word,X,31,986
|
|
||||||
fabs[.],Floating Absolute Value,X,63,264
|
|
||||||
fadd[.],Floating Add,A,63,21
|
|
||||||
fadds[.],Floating Add Single,A,59,21
|
|
||||||
fcfid,Floating Convert from Integer Doubleword,X,63,846
|
|
||||||
fcmpo,Floating Compare Ordered,X,63,32
|
|
||||||
fcmpu,Floating Compare Unordered,XL,63,0
|
|
||||||
fctid,Floating Convert to Integer Doubleword,X,63,814
|
|
||||||
fctidz,Floating Convert to Integer Doubleword with Round Toward Zero,X,63,815
|
|
||||||
fctiw[.],Floating Convert to Integer Word,X,63,14
|
|
||||||
fctiwz[.],Floating Convert to Integer Word with Round to Zero,XL,63,15
|
|
||||||
fdiv[.],Floating Divide,A,63,18
|
|
||||||
fdivs[.],Floating Divide Single,A,59,18
|
|
||||||
fmadd[.],Floating Multiply-Add,A,63,29
|
|
||||||
fmadds[.],Floating Multiply-Add Single,A,59,29
|
|
||||||
fmr[.],Floating Move Register,X,63,72
|
|
||||||
fmsub[.],Floating Multiply-Subtract,A,63,28
|
|
||||||
fmsubs[.],Floating Multiply-Subtract Single,A,59,28
|
|
||||||
fmul[.],Floating Multiply,A,63,25
|
|
||||||
fmuls[.],Floating Multiply Single,A,59,25
|
|
||||||
fnabs[.],Floating Negative Absolute Value,X,63,136
|
|
||||||
fneg[.],Floating Negate,X,63,40
|
|
||||||
fnmadd[.],Floating Negative Multiply-Add,A,63,31
|
|
||||||
fnmadds[.],Floating Negative Multiply-Add Single,A,59,31
|
|
||||||
fnmsub[.],Floating Negative Multiply-Subtract,A,63,30
|
|
||||||
fnmsubs[.],Floating Negative Multiply-Subtract Single,A,59,30
|
|
||||||
fres[.],Floating Reciprocal Estimate Single (optional),A,59,24
|
|
||||||
frsp[.],Floating Round to Single Precision,X,63,12
|
|
||||||
frsqrte[.],Floating Reciprocal Square Root Estimate (optional),A,63,26
|
|
||||||
fsel[.],Floating-Point Select (optional),A,63,23
|
|
||||||
fsub[.],Floating Subtract,A,63,20
|
|
||||||
fsubs[.],Floating Subtract Single,A,59,20
|
|
||||||
icbi,Instruction Cache Block Invalidate,X,31,982
|
|
||||||
isync,Instruction Synchronize,X,19,150
|
|
||||||
lbz,Load Byte and Zero,D,34,
|
|
||||||
lbzu,Load Byte and Zero with Update,D,35,
|
|
||||||
lbzux,Load Byte and Zero with Update Indexed,X,31,119
|
|
||||||
lbzx,Load Byte and Zero Indexed,X,31,87
|
|
||||||
ld,Load Doubleword,DS,58,0
|
|
||||||
ldarx,Load Doubleword and Reserve Indexed,X,31,84
|
|
||||||
ldu,Load Doubleword with Update,DS,58,1
|
|
||||||
ldux,Load Doubleword with Update Indexed,X,31,53
|
|
||||||
ldx,Load Doubleword Indexed,X,31,21
|
|
||||||
lfd,Load Floating-Point Double,D,50,
|
|
||||||
lfdu,Load Floating-Point Double with Update,D,51,
|
|
||||||
lfdux,Load Floating-Point Double with Update Indexed,X,31,631
|
|
||||||
lfdx,Load Floating-Point Double Indexed,X,31,599
|
|
||||||
lfs,Load Floating-Point Single,D,48,
|
|
||||||
lfsu,Load Floating-Point Single with Update,D,49,
|
|
||||||
lfsux,Load Floating-Point Single with Update Indexed,X,31,567
|
|
||||||
lfsx,Load Floating-Point Single Indexed,X,31,535
|
|
||||||
lha,Load Half Algebraic,D,42,
|
|
||||||
lhau,Load Half Algebraic with Update,D,43,
|
|
||||||
lhaux,Load Half Algebraic with Update Indexed,X,31,375
|
|
||||||
lhax,Load Half Algebraic Indexed,X,31,343
|
|
||||||
lhbrx,Load Half Byte-Reversed Indexed,X,31,790
|
|
||||||
lhz,Load Half and Zero,D,40,
|
|
||||||
lhzu,Load Half and Zero with Update,D,41,
|
|
||||||
lhzux,Load Half and Zero with Update Indexed,X,31,331
|
|
||||||
lhzx,Load Half and Zero Indexed,X,31,279
|
|
||||||
lmw,Load Multiple Word,D,46,
|
|
||||||
lswi,Load String Word Immediate,X,31,597
|
|
||||||
lswx,Load String Word Indexed,X,31,533
|
|
||||||
lwa,Load Word Algebraic,DS,58,2
|
|
||||||
lwarx,Load Word and Reserve Indexed,X,31,20
|
|
||||||
lwaux,Load Word Algebraic with Update Indexed,X,31,373
|
|
||||||
lwax,Load Word Algebraic Indexed,X,31,341
|
|
||||||
lwbrx,Load Word Byte-Reversed Indexed,X,31,534
|
|
||||||
lwz,Load Word and Zero,D,32,
|
|
||||||
lwzu,Load Word with Zero Update,D,33,
|
|
||||||
lwzux,Load Word and Zero with Update Indexed,X,31,55
|
|
||||||
lwzx,Load Word and Zero Indexed,X,31,23
|
|
||||||
mcrf,Move Condition Register Field,XL,19,0
|
|
||||||
mcrfs,Move to Condition Register from FPSCR,X,63,64
|
|
||||||
mcrxr,Move to Condition Register from XER,X,31,512
|
|
||||||
mfcr,Move from Condition Register,X,31,19
|
|
||||||
mffs[.],Move from FPSCR,X,63,583
|
|
||||||
mfmsr,Move from Machine State Register,X,31,83
|
|
||||||
mfspr,Move from Special-Purpose Register,X,31,339
|
|
||||||
mfsr,Move from Segment Register,X,31,595
|
|
||||||
mfsrin,Move from Segment Register Indirect,X,31,659
|
|
||||||
mtcrf,Move to Condition Register Fields,XFX,31,144
|
|
||||||
mtfsb0[.],Move to FPSCR Bit 0,X,63,70
|
|
||||||
mtfsb1[.],Move to FPSCR Bit 1,X,63,38
|
|
||||||
mtfsf[.],Move to FPSCR Fields,XFL,63,711
|
|
||||||
mtfsfi[.],Move to FPSCR Field Immediate,X,63,134
|
|
||||||
mtmsr,Move to Machine State Register,X,31,146
|
|
||||||
mtspr,Move to Special-Purpose Register,X,31,467
|
|
||||||
mtsr,Move to Segment Register,X,31,210
|
|
||||||
mtsrin,Move to Segment Register Indirect,X,31,242
|
|
||||||
mulhd,Multiply High Doubleword,XO,31,73
|
|
||||||
mulhdu,Multiply High Doubleword Unsigned,XO,31,9
|
|
||||||
mulhw[.],Multiply High Word,XO,31,75
|
|
||||||
mulhwu[.],Multiply High Word Unsigned,XO,31,11
|
|
||||||
mulld,Multiply Low Doubleword,XO,31,233
|
|
||||||
mulli,Multiply Low Immediate,D,07,
|
|
||||||
mullw[o][.],Multiply Low Word,XO,31,235
|
|
||||||
nand[.],NAND,X,31,476
|
|
||||||
neg[o][.],Negate,XO,31,104
|
|
||||||
nor[.],NOR,X,31,124
|
|
||||||
or[.],OR,X,31,444
|
|
||||||
orc[.],OR with Complement,X,31,412
|
|
||||||
ori,OR Immediate,D,24,
|
|
||||||
oris,OR Immediate Shifted,D,25,
|
|
||||||
rfi,Return from Interrupt,X,19,50
|
|
||||||
rldcl,Rotate Left Doubleword then Clear Left,MDS,30,8
|
|
||||||
rldcr,Rotate Left Doubleword then Clear Right,MDS,30,9
|
|
||||||
rldic,Rotate Left Doubleword Immediate then Clear,MD,30,2
|
|
||||||
rldicl,Rotate Left Doubleword Immediate then Clear Left,MD,30,0
|
|
||||||
rldicr,Rotate Left Doubleword Immediate then Clear Right,MD,30,1
|
|
||||||
rldimi,Rotate Left Doubleword Immediate then Mask Insert,MD,30,3
|
|
||||||
rlwimi[.],Rotate Left Word Immediate then Mask Insert,M,20,
|
|
||||||
rlwinm[.],Rotate Left Word Immediate then AND with Mask,M,21,
|
|
||||||
rlwnm[.],Rotate Left Word then AND with Mask,M,23,
|
|
||||||
sc,System Call,SC,17,
|
|
||||||
si,Subtract Immediate,D,12,
|
|
||||||
si.,Subtract Immediate and Record,D,13,
|
|
||||||
slbia,SLB Invalidate All,X,31,498
|
|
||||||
slbie,SLB Invalidate Entry,X,31,434
|
|
||||||
sld,Shift Left Doubleword,X,31,27
|
|
||||||
slw[.],Shift Left Word,X,31,24
|
|
||||||
srad,Shift Right Algebraic Doubleword,X,31,794
|
|
||||||
sradi,Shift Right Algebraic Doubleword Immediate,XS,31,413
|
|
||||||
srd,Shift Right Doubleword,X,31,539
|
|
||||||
sraw[.],Shift Right Algebraic Word,X,31,792
|
|
||||||
srawi[.],Shift Right Algebraic Word Immediate,X,31,824
|
|
||||||
srw[.],Shift Right Word,X,31,536
|
|
||||||
stb,Store Byte,D,38,
|
|
||||||
stbu,Store Byte with Update,D,39,
|
|
||||||
stbux,Store Byte with Update Indexed,X,31,247
|
|
||||||
stbx,Store Byte Indexed,X,31,215
|
|
||||||
std,Store Doubleword,DS,62,0
|
|
||||||
stdcx,Store Doubleword Conditional Indexed,X,31,214
|
|
||||||
stdu,Store Doubleword with Update,DS,62,1
|
|
||||||
stdux,Store Doubleword with Update Indexed,X,31,181
|
|
||||||
stdx,Store Doubleword Indexed,X,31,149
|
|
||||||
stfd,Store Floating-Point Double,D,54,
|
|
||||||
stfdu,Store Floating-Point Double with Update,D,55,
|
|
||||||
stfdux,Store Floating-Point Double with Update Indexed,X,31,759
|
|
||||||
stfdx,Store Floating-Point Double Indexed,X,31,727
|
|
||||||
stfiwx,Store Floating-Point as Integer Word Indexed (optional),X,31,983
|
|
||||||
stfs,Store Floating-Point Single,D,52,
|
|
||||||
stfsu,Store Floating-Point Single with Update,D,53,
|
|
||||||
stfsux,Store Floating-Point Single with Update Indexed,X,31,695
|
|
||||||
stfsx,Store Floating-Point Single Indexed,X,31,663
|
|
||||||
sth,Store Half,D,44,
|
|
||||||
sthbrx,Store Half Byte-Reverse Indexed,X,31,918
|
|
||||||
sthu,Store Half with Update,D,45,
|
|
||||||
sthux,Store Half with Update Indexed,X,31,439
|
|
||||||
sthx,Store Half Indexed,X,31,407
|
|
||||||
stmw,Store Multiple Word,D,47,
|
|
||||||
stswi,Store String Word Immediate,X,31,725
|
|
||||||
stswx,Store String Word Indexed,X,31,661
|
|
||||||
stw,Store,D,36,
|
|
||||||
stwbrx,Store Word Byte-Reversed Indexed,X,31,662
|
|
||||||
stwcx.,Store Word Conditional Indexed,X,31,150
|
|
||||||
stwu,Store Word with Update,D,37,
|
|
||||||
stwux,Store Word with Update Indexed,X,31,183
|
|
||||||
stwx,Store Word Indexed,X,31,151
|
|
||||||
subf[o][.],Subtract from,XO,31,40
|
|
||||||
subfc[o][.],Subtract from Carrying,XO,31,08
|
|
||||||
subfe[o][.],Subtract from Extended,XO,31,136
|
|
||||||
subfic,Subtract from Immediate Carrying,D,08,
|
|
||||||
subfme[o][.],Subtract from Minus One Extended,XO,31,232
|
|
||||||
subfze[o][.],Subtract from Zero Extended,XO,31,200
|
|
||||||
sync,Synchronize,X,31,598
|
|
||||||
td,Trap Doubleword,X,31,68
|
|
||||||
tdi,Trap Doubleword Immediate,D,2,
|
|
||||||
tlbie,Translation Look-aside Buffer Invalidate Entry (optional),X,31,306
|
|
||||||
tlbsync,Translation Look-aside Buffer Synchronize (optional),X,31,566
|
|
||||||
tw,Trap Word,X,31,04
|
|
||||||
twi,Trap Word Immediate,D,03,
|
|
||||||
xor[.],XOR,X,31,316
|
|
||||||
xori,XOR Immediate,D,26,
|
|
||||||
xoris,XOR Immediate Shift,D,27,
|
|
||||||
Vendored
-343
@@ -1,343 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string.h>
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
printf(
|
|
||||||
"// this file is autogenerated DO NOT MODIFY\n"
|
|
||||||
"#pragma once\n"
|
|
||||||
);
|
|
||||||
FILE* fp = fopen(argv[1], "rt");
|
|
||||||
if (fp) {
|
|
||||||
char line[80];
|
|
||||||
while (fgets(line, sizeof line, fp) != NULL) {
|
|
||||||
bool with_o = strstr(line, "[o]"), with_d = strstr(line, "[.]");
|
|
||||||
char* p = strchr(line, '\n'), *name = strchr(line, ','), *mem = line;
|
|
||||||
if (p) *p = '\0';
|
|
||||||
if (name) {
|
|
||||||
*name++ = '\0';
|
|
||||||
char *form = strchr(name, ',');
|
|
||||||
if (form) {
|
|
||||||
*form++ = '\0';
|
|
||||||
char *opc = strchr(form, ',');
|
|
||||||
if (opc) {
|
|
||||||
*opc++ = '\0';
|
|
||||||
char *sec = strchr(opc, ',');
|
|
||||||
if (sec) {
|
|
||||||
struct b_info { const char *s; int o; int p; } infos[] = {
|
|
||||||
{"",1,0},
|
|
||||||
{"LT",1,12},
|
|
||||||
{"LE",2,4},
|
|
||||||
{"NG",2,4},
|
|
||||||
{"EQ",3,12},
|
|
||||||
{"GE",1,4},
|
|
||||||
{"NL",1,4},
|
|
||||||
{"GT",2,12},
|
|
||||||
{"NE",3,4},
|
|
||||||
{"SO",4,12},
|
|
||||||
{"UN",4,12},
|
|
||||||
{"NS",4,4},
|
|
||||||
{"NU",4,4},
|
|
||||||
};
|
|
||||||
#define OP_EXT ((i_opcode << 26) | (i_extopc << 1))
|
|
||||||
if (strchr(mem, '[') != NULL) *strchr(mem, '[') = '\0';
|
|
||||||
if (strchr(mem, '.') != NULL) *strchr(mem, '.') = '_';
|
|
||||||
*sec++ = '\0';
|
|
||||||
for (int i = 0; i < strlen(mem); ++i)
|
|
||||||
mem[i] = toupper(mem[i]);
|
|
||||||
int i_opcode = atoi(opc);
|
|
||||||
int i_extopc = atoi(sec);
|
|
||||||
//printf("// %s\n", mem);
|
|
||||||
if (!strcmp(form, "XO")) {
|
|
||||||
if (!strcmp(mem, "EXTSH")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, false, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sC(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, true, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, false, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sC_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, true, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, false, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sO(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, true, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, false, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sO_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, true, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "X")) {
|
|
||||||
if (!strcmp(mem, "CMPL") || !strcmp(mem, "CMP")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, rb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(mem, "CNTLZD") || !strcmp(mem, "CNTLZW") || !strcmp(mem, "EXTSB") || !strcmp(mem, "EXTSH") || !strcmp(mem, "EXTSW")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, R0, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, R0, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, rb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, rb, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "I")) {
|
|
||||||
printf(
|
|
||||||
"void %s(Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, i, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
printf(
|
|
||||||
"void %sL(Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, i, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(form, "B")) {
|
|
||||||
for (int i = 0; i < 12; ++i) {
|
|
||||||
printf(
|
|
||||||
"void %s%s(CPR const cr, Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
|
||||||
printf(
|
|
||||||
"void %s%sL(CPR const cr, Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
|
||||||
if (!strcmp(mem, "BC")) mem[1] = '\0';
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "D")) {
|
|
||||||
if (!strcmp(mem, "CMPLI") || !strcmp(mem, "CMPI")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(mem, "ANDIS_") || !strcmp(mem, "ANDI_")
|
|
||||||
|| !strcmp(mem, "ORI") || !strcmp(mem, "ORIS")
|
|
||||||
|| !strcmp(mem, "XORI") || !strcmp(mem, "XORIS")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "SC")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t lev) {"
|
|
||||||
" emit_%s(0x%08x, lev); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(form, "DS")) {
|
|
||||||
#define OP_EXT_DS ((i_opcode << 26) | (i_extopc << 0))
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, d >> 2); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_DS);
|
|
||||||
#undef OP_EXT_DS
|
|
||||||
} else if (!strcmp(form, "XS")) {
|
|
||||||
#define OP_EXT_XS ((i_opcode << 26) | (i_extopc << 2))
|
|
||||||
/* HUGE DIFFERENCE DO NOT REMOVE */
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, sh, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_XS);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, sh, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_XS);
|
|
||||||
#undef OP_EXT_XS
|
|
||||||
} else if (!strcmp(form, "XL")) {
|
|
||||||
if (!strcmp(mem, "BCLR")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
if (!strcmp(mem, "BCLR")) mem[1] = '\0';
|
|
||||||
for (int i = 1; i < 12; ++i) {
|
|
||||||
printf(
|
|
||||||
"void %s%sLR(CPR const cr) {"
|
|
||||||
" emit_%s(0x%08x, %i, cr.index + %i, 0, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
|
||||||
printf(
|
|
||||||
"void %s%sLRL(CPR const cr) {"
|
|
||||||
" emit_%s(0x%08x, %i, cr.index + %i, 0, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
|
||||||
}
|
|
||||||
} else if (mem[0] == 'B') {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, Cond const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, Cond const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(CPR const bt, CPR const ba, CPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(CPR const bt, CPR const ba, CPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "M")) {
|
|
||||||
if (!strcmp(mem, "RLWNM")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, sh, mb, me, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, sh, mb, me, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "MD")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, mb, sh, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, mb, sh, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
|
||||||
} else if (!strcmp(form, "MDS")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb, mb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb, mb, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(form, "A")) {
|
|
||||||
printf(
|
|
||||||
"void %s(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
|
||||||
" emit_%s(0x%08x, frt, fra, frb, frc, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
|
||||||
" emit_%s(0x%08x, frt, fra, frb, frc, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(form, "XFX")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, uint32_t spr) {"
|
|
||||||
" emit_%s(0x%08x, rt, spr); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s() {"
|
|
||||||
" emit_%s(0x%08x); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//printf("%s\n", line);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Vendored
-401
@@ -1,401 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#undef NDEBUG
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
|
||||||
#include <utility>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
//#ifndef __cpp_lib_unreachable
|
|
||||||
namespace std {
|
|
||||||
[[noreturn]] inline void unreachable() {
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
|
||||||
__assume(false);
|
|
||||||
#else // GCC, Clang
|
|
||||||
__builtin_unreachable();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
namespace powah {
|
|
||||||
|
|
||||||
// Symbolic conditions
|
|
||||||
enum class Cond : uint8_t {
|
|
||||||
LT, LE, NG, EQ, GE, NL, GT, NE, SO, UN, NS, NU
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GPR { uint32_t index; };
|
|
||||||
struct FPR { uint32_t index; };
|
|
||||||
struct VPR { uint32_t index; };
|
|
||||||
struct CPR { uint32_t index; };
|
|
||||||
struct Label { uint32_t index; };
|
|
||||||
|
|
||||||
constexpr inline GPR R0{0};
|
|
||||||
constexpr inline GPR R1{1};
|
|
||||||
constexpr inline GPR R2{2};
|
|
||||||
constexpr inline GPR R3{3};
|
|
||||||
constexpr inline GPR R4{4};
|
|
||||||
constexpr inline GPR R5{5};
|
|
||||||
constexpr inline GPR R6{6};
|
|
||||||
constexpr inline GPR R7{7};
|
|
||||||
constexpr inline GPR R8{8};
|
|
||||||
constexpr inline GPR R9{9};
|
|
||||||
constexpr inline GPR R10{10};
|
|
||||||
constexpr inline GPR R11{11};
|
|
||||||
constexpr inline GPR R12{12};
|
|
||||||
constexpr inline GPR R13{13};
|
|
||||||
constexpr inline GPR R14{14};
|
|
||||||
constexpr inline GPR R15{15};
|
|
||||||
constexpr inline GPR R16{16};
|
|
||||||
constexpr inline GPR R17{17};
|
|
||||||
constexpr inline GPR R18{18};
|
|
||||||
constexpr inline GPR R19{19};
|
|
||||||
constexpr inline GPR R20{20};
|
|
||||||
constexpr inline GPR R21{21};
|
|
||||||
constexpr inline GPR R22{22};
|
|
||||||
constexpr inline GPR R23{23};
|
|
||||||
constexpr inline GPR R24{24};
|
|
||||||
constexpr inline GPR R25{25};
|
|
||||||
constexpr inline GPR R26{26};
|
|
||||||
constexpr inline GPR R27{27};
|
|
||||||
constexpr inline GPR R28{28};
|
|
||||||
constexpr inline GPR R29{29};
|
|
||||||
constexpr inline GPR R30{30};
|
|
||||||
constexpr inline GPR R31{31};
|
|
||||||
|
|
||||||
constexpr inline FPR FR0{0};
|
|
||||||
constexpr inline FPR FR1{1};
|
|
||||||
constexpr inline FPR FR2{2};
|
|
||||||
constexpr inline FPR FR3{3};
|
|
||||||
constexpr inline FPR FR4{4};
|
|
||||||
constexpr inline FPR FR5{5};
|
|
||||||
constexpr inline FPR FR6{6};
|
|
||||||
constexpr inline FPR FR7{7};
|
|
||||||
constexpr inline FPR FR8{8};
|
|
||||||
constexpr inline FPR FR9{9};
|
|
||||||
constexpr inline FPR FR10{10};
|
|
||||||
constexpr inline FPR FR11{11};
|
|
||||||
constexpr inline FPR FR12{12};
|
|
||||||
constexpr inline FPR FR13{13};
|
|
||||||
constexpr inline FPR FR14{14};
|
|
||||||
constexpr inline FPR FR15{15};
|
|
||||||
constexpr inline FPR FR16{16};
|
|
||||||
constexpr inline FPR FR17{17};
|
|
||||||
constexpr inline FPR FR18{18};
|
|
||||||
constexpr inline FPR FR19{19};
|
|
||||||
constexpr inline FPR FR20{20};
|
|
||||||
constexpr inline FPR FR21{21};
|
|
||||||
constexpr inline FPR FR22{22};
|
|
||||||
constexpr inline FPR FR23{23};
|
|
||||||
constexpr inline FPR FR24{24};
|
|
||||||
constexpr inline FPR FR25{25};
|
|
||||||
constexpr inline FPR FR26{26};
|
|
||||||
constexpr inline FPR FR27{27};
|
|
||||||
constexpr inline FPR FR28{28};
|
|
||||||
constexpr inline FPR FR29{29};
|
|
||||||
constexpr inline FPR FR30{30};
|
|
||||||
constexpr inline FPR FR31{31};
|
|
||||||
|
|
||||||
// They call it CPR because when programmers see this code they-
|
|
||||||
constexpr inline CPR CR0{0};
|
|
||||||
constexpr inline CPR CR1{4};
|
|
||||||
constexpr inline CPR CR2{8};
|
|
||||||
constexpr inline CPR CR3{12};
|
|
||||||
constexpr inline CPR CR4{16};
|
|
||||||
constexpr inline CPR CR5{20};
|
|
||||||
constexpr inline CPR CR6{24};
|
|
||||||
constexpr inline CPR CR7{28};
|
|
||||||
|
|
||||||
constexpr uint32_t XER_SO = 32;
|
|
||||||
constexpr uint32_t XER_OV = 33;
|
|
||||||
constexpr uint32_t XER_CA = 34;
|
|
||||||
|
|
||||||
enum class RelocKind : uint8_t {
|
|
||||||
FormB,
|
|
||||||
FormI,
|
|
||||||
};
|
|
||||||
struct RelocInfo {
|
|
||||||
uint32_t offset;
|
|
||||||
RelocKind kind;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Context {
|
|
||||||
Context() = default;
|
|
||||||
Context(void* ptr, size_t size)
|
|
||||||
: base{reinterpret_cast<uint32_t*>(ptr)}
|
|
||||||
, offset{0}
|
|
||||||
, size{uint32_t(size)} {
|
|
||||||
|
|
||||||
}
|
|
||||||
~Context() = default;
|
|
||||||
|
|
||||||
std::vector<uint32_t> labels;
|
|
||||||
std::vector<std::pair<uint32_t, RelocInfo>> relocs;
|
|
||||||
|
|
||||||
Label DefineLabel() {
|
|
||||||
labels.push_back(0);
|
|
||||||
return Label{ uint32_t(labels.size() - 1) };
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyRelocs() {
|
|
||||||
for (auto const &[index, info] : relocs) {
|
|
||||||
//assert(labels[index] != 0); //label must have an addr
|
|
||||||
int32_t rel = (int32_t)labels[index] - (int32_t)info.offset;
|
|
||||||
switch (info.kind) {
|
|
||||||
case RelocKind::FormB:
|
|
||||||
base[info.offset] |= bitExt(rel, 16, 14);
|
|
||||||
break;
|
|
||||||
case RelocKind::FormI:
|
|
||||||
base[info.offset] |= bitExt(rel, 6, 24);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
relocs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LABEL(Label l) {
|
|
||||||
assert(labels[l.index] == 0);
|
|
||||||
labels[l.index] = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr uint32_t cond2offset(Cond c) noexcept {
|
|
||||||
switch (c) {
|
|
||||||
case Cond::LT: return 1;
|
|
||||||
case Cond::LE: return 2;
|
|
||||||
case Cond::NG: return 2;
|
|
||||||
case Cond::EQ: return 3;
|
|
||||||
case Cond::GE: return 1;
|
|
||||||
case Cond::NL: return 1;
|
|
||||||
case Cond::GT: return 2;
|
|
||||||
case Cond::NE: return 3;
|
|
||||||
case Cond::SO: return 4;
|
|
||||||
case Cond::UN: return 4;
|
|
||||||
case Cond::NS: return 4;
|
|
||||||
case Cond::NU: return 4;
|
|
||||||
default: return 0; //hopefully icc isn't stupid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t bitExt(uint32_t value, uint32_t offs, uint32_t n) {
|
|
||||||
uint32_t mask = (1UL << n) - 1;
|
|
||||||
return (value & mask) << (32 - (n + offs));
|
|
||||||
}
|
|
||||||
void emit_XO(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool oe, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| bitExt(oe, 21, 1)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_D(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| (d & 0xffff)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_X(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XS(uint32_t op, GPR const rt, GPR const ra, uint32_t sh, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
((rt.index & 0x1f) << 16)
|
|
||||||
| ((ra.index & 0x1f) << 21)
|
|
||||||
| ((sh & 0x1f) << 11)
|
|
||||||
| ((sh >> 4) & 0x02)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_reloc_I(uint32_t op, Label const& l, bool lk) {
|
|
||||||
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormI });
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_reloc_B(uint32_t op, uint32_t bo, uint32_t cri, Label const& l, bool lk) {
|
|
||||||
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormB });
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(bo, 6, 5)
|
|
||||||
| bitExt(cri, 11, 5)
|
|
||||||
| bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XL(uint32_t op, uint32_t bt, uint32_t ba, uint32_t bb, bool lk) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(bt, 6, 5)
|
|
||||||
| bitExt(ba, 11, 5)
|
|
||||||
| bitExt(bb, 16, 5)
|
|
||||||
| bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_A(uint32_t op, FPR const frt, FPR const fra, FPR const frb, FPR const frc, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(frt.index, 6, 5)
|
|
||||||
| bitExt(fra.index, 11, 5)
|
|
||||||
| bitExt(frb.index, 16, 5)
|
|
||||||
| bitExt(frc.index, 21, 5)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_DS(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
|
||||||
//assert(d & 0x03 == 0);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(d, 16, 14)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_M(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me, bool rc) {
|
|
||||||
assert(sh <= 0x3f && mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| ((sh & 0x1f) << 11)
|
|
||||||
| ((mb & 0x1f) << 6)
|
|
||||||
| ((me & 0x1f) << 1)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MD(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
|
||||||
assert(mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MD(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, bool rc) {
|
|
||||||
assert(sh <= 0x3f && mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| ((sh & 0x1f) << 11) | ((sh >> 4) & 0x02)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MDS(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XFL(uint32_t op) {
|
|
||||||
(void)op;
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
void emit_XFX(uint32_t op, GPR const rt, uint32_t spr) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
(rt.index & 0x1f) << 21
|
|
||||||
| ((spr & 0xff) << 12)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_SC(uint32_t op, uint32_t lev) {
|
|
||||||
(void)op;
|
|
||||||
(void)lev;
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended Memmonics, hand coded :)
|
|
||||||
void MR(GPR const ra, GPR const rs) { OR(ra, rs, rs); }
|
|
||||||
void NOP() { ORI(R0, R0, 0); }
|
|
||||||
void NOT(GPR const ra, GPR const rs) { NOR(ra, rs, rs); }
|
|
||||||
|
|
||||||
void ROTLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, n, 0); }
|
|
||||||
void ROTRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, 0); }
|
|
||||||
|
|
||||||
void ROTLWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, n, 0, 31); }
|
|
||||||
void ROTRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, 0, 31); }
|
|
||||||
|
|
||||||
void ROTLW(GPR const ra, GPR const rs, GPR const rb) { RLWNM(ra, rs, rb, 0, 31); }
|
|
||||||
void ROTLD(GPR const ra, GPR const rs, GPR const rb) { RLDCL(ra, rs, rb, 0); }
|
|
||||||
|
|
||||||
void EXTLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, b, n - 1); }
|
|
||||||
void SLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, n, 63 - n); }
|
|
||||||
void CLRLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 0, n); }
|
|
||||||
|
|
||||||
void EXTRDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICL(ra, rs, b + n, 64 - n); }
|
|
||||||
void SRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, n); }
|
|
||||||
void CLLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, 0, n); }
|
|
||||||
void CLRSLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, n, b - n); }
|
|
||||||
|
|
||||||
void EXTLWI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLWINM(ra, rs, b, 0, n - 1); }
|
|
||||||
void SRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, n, 31); }
|
|
||||||
void CLRRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 0, 0, 31 - n); }
|
|
||||||
|
|
||||||
void CRSET(CPR const bx) { CREQV(bx, bx, bx); }
|
|
||||||
void CRCLR(CPR const bx) { CRXOR(bx, bx, bx); }
|
|
||||||
void CRMOVE(CPR const bx, CPR const by) { CROR(bx, by, by); }
|
|
||||||
void CRNOT(CPR const bx, CPR const by) { CRNOR(bx, by, by); }
|
|
||||||
|
|
||||||
void CMPLDI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 1, rx, v); }
|
|
||||||
void CMPLWI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 0, rx, v); }
|
|
||||||
void CMPLD(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 1, rx, ry); }
|
|
||||||
void CMPLW(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 0, rx, ry); }
|
|
||||||
void CMPLDI(GPR const rx, uint32_t v) { CMPLI(0, 1, rx, v); }
|
|
||||||
void CMPLWI(GPR const rx, uint32_t v) { CMPLI(0, 0, rx, v); }
|
|
||||||
void CMPLD(GPR const rx, GPR const ry) { CMPL(0, 1, rx, ry); }
|
|
||||||
void CMPLW(GPR const rx, GPR const ry) { CMPL(0, 0, rx, ry); }
|
|
||||||
|
|
||||||
void CMPWI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 0, rx, si); }
|
|
||||||
void CMPW(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 0, rx, ry); }
|
|
||||||
void CMPDI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 1, rx, si); }
|
|
||||||
void CMPD(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 1, rx, ry); }
|
|
||||||
void CMPWI(GPR const rx, uint32_t si) { CMPI(0, 0, rx, si); }
|
|
||||||
void CMPW(GPR const rx, GPR const ry) { CMP(0, 0, rx, ry); }
|
|
||||||
void CMPDI(GPR const rx, uint32_t si) { CMPI(0, 1, rx, si); }
|
|
||||||
void CMPD(GPR const rx, GPR const ry) { CMP(0, 1, rx, ry); }
|
|
||||||
|
|
||||||
void LI(GPR const rx, uint32_t value) { ADDI(rx, R0, value); }
|
|
||||||
void LIS(GPR const rx, uint32_t value) { ADDIS(rx, R0, value); }
|
|
||||||
|
|
||||||
void MFLR(GPR const rt) { MFSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
|
||||||
void MTLR(GPR const rt) { MTSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
|
||||||
void BLR() { base[offset++] = 0x4e800020; } //BCLR(R0, CR0, R0);
|
|
||||||
|
|
||||||
void MFCTR(GPR const rt) { MFSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
|
||||||
void MTCTR(GPR const rt) { MTSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
|
||||||
void BCTRL() { base[offset++] = 0x4e800421; } //BCCTRL(R0, CR0, R0);
|
|
||||||
void BCTR() { base[offset++] = 0x4e800420; } //BCCTR(R0, CR0, R0);
|
|
||||||
|
|
||||||
// TODO: PowerPC 11 stuff
|
|
||||||
void ISEL(GPR const rd, GPR const ra, GPR const rb, uint32_t d) {
|
|
||||||
(void)rd;
|
|
||||||
(void)ra;
|
|
||||||
(void)rb;
|
|
||||||
(void)d;
|
|
||||||
std::unreachable();
|
|
||||||
}
|
|
||||||
void ISELLT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 0); }
|
|
||||||
void ISELGT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 1); }
|
|
||||||
void ISELEQ(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 2); }
|
|
||||||
|
|
||||||
// Rawly pasted because fuck you
|
|
||||||
#include "powah_gen_base.hpp"
|
|
||||||
|
|
||||||
uint32_t* base = nullptr;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
Vendored
-487
@@ -1,487 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// this file is autogenerated DO NOT MODIFY
|
|
||||||
#pragma once
|
|
||||||
void ADD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, false); }
|
|
||||||
void ADDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, false); }
|
|
||||||
void ADD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, true); }
|
|
||||||
void ADDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, true); }
|
|
||||||
void ADDC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, false); }
|
|
||||||
void ADDCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, false); }
|
|
||||||
void ADDC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, true); }
|
|
||||||
void ADDCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, true); }
|
|
||||||
void ADDE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, false); }
|
|
||||||
void ADDEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, false); }
|
|
||||||
void ADDE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, true); }
|
|
||||||
void ADDEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, true); }
|
|
||||||
void ADDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x38000000, rt, ra, d); }
|
|
||||||
void ADDIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
|
||||||
void ADDIC_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
|
||||||
void ADDIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x3c000000, rt, ra, d); }
|
|
||||||
void ADDME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, false); }
|
|
||||||
void ADDMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, false); }
|
|
||||||
void ADDME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, true); }
|
|
||||||
void ADDMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, true); }
|
|
||||||
void ADDZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, false); }
|
|
||||||
void ADDZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, false); }
|
|
||||||
void ADDZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, true); }
|
|
||||||
void ADDZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, true); }
|
|
||||||
void AND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, false); }
|
|
||||||
void AND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, true); }
|
|
||||||
void ANDC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, false); }
|
|
||||||
void ANDC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, true); }
|
|
||||||
void ANDI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x70000000, ra, rt, d); }
|
|
||||||
void ANDIS_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x74000000, ra, rt, d); }
|
|
||||||
void B(Label const& i) { emit_reloc_I(0x48000000, i, false); }
|
|
||||||
void BL(Label const& i) { emit_reloc_I(0x48000000, i, true); }
|
|
||||||
void BC(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, false); }
|
|
||||||
void BCL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, true); }
|
|
||||||
void BLT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, false); }
|
|
||||||
void BLTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, true); }
|
|
||||||
void BLE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
|
||||||
void BLEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
|
||||||
void BNG(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
|
||||||
void BNGL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
|
||||||
void BEQ(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, false); }
|
|
||||||
void BEQL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, true); }
|
|
||||||
void BGE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
|
||||||
void BGEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
|
||||||
void BNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
|
||||||
void BNLL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
|
||||||
void BGT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, false); }
|
|
||||||
void BGTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, true); }
|
|
||||||
void BNE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, false); }
|
|
||||||
void BNEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, true); }
|
|
||||||
void BSO(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
|
||||||
void BSOL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
|
||||||
void BUN(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
|
||||||
void BUNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
|
||||||
void BNS(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, false); }
|
|
||||||
void BNSL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, true); }
|
|
||||||
void BCCTR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, false); }
|
|
||||||
void BCCTRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, true); }
|
|
||||||
void BCCTR(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, false); }
|
|
||||||
void BCCTRL(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, true); }
|
|
||||||
void BCLR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, false); }
|
|
||||||
void BCLRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, true); }
|
|
||||||
void BLTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, false); }
|
|
||||||
void BLTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, true); }
|
|
||||||
void BLELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
|
||||||
void BLELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
|
||||||
void BNGLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
|
||||||
void BNGLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
|
||||||
void BEQLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, false); }
|
|
||||||
void BEQLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, true); }
|
|
||||||
void BGELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
|
||||||
void BGELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
|
||||||
void BNLLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
|
||||||
void BNLLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
|
||||||
void BGTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, false); }
|
|
||||||
void BGTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, true); }
|
|
||||||
void BNELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, false); }
|
|
||||||
void BNELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, true); }
|
|
||||||
void BSOLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
|
||||||
void BSOLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
|
||||||
void BUNLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
|
||||||
void BUNLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
|
||||||
void BNSLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, false); }
|
|
||||||
void BNSLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, true); }
|
|
||||||
void CMP(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000000, GPR{(bf << 2) | l}, ra, rb, false); }
|
|
||||||
void CMPI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x2c000000, GPR{(bf << 2) | l}, ra, d); }
|
|
||||||
void CMPL(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000040, GPR{(bf << 2) | l}, ra, rb, false); }
|
|
||||||
void CMPLI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x28000000, GPR{(bf << 2) | l}, ra, d); }
|
|
||||||
void CNTLZD(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, false); }
|
|
||||||
void CNTLZD_(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, true); }
|
|
||||||
void CNTLZW(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, false); }
|
|
||||||
void CNTLZW_(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, true); }
|
|
||||||
void CRAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRANDC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRANDCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CREQV(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CREQVL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRNAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRNANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRNOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRNORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CROR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRORC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRORCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRXOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRXORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, true); }
|
|
||||||
void DCBF(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, false); }
|
|
||||||
void DCBF_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, true); }
|
|
||||||
void DCBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, false); }
|
|
||||||
void DCBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, true); }
|
|
||||||
void DCBST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, false); }
|
|
||||||
void DCBST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, true); }
|
|
||||||
void DCBT(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, false); }
|
|
||||||
void DCBT_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, true); }
|
|
||||||
void DCBTST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, false); }
|
|
||||||
void DCBTST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, true); }
|
|
||||||
void DCBZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, false); }
|
|
||||||
void DCBZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, true); }
|
|
||||||
void DIVD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, false); }
|
|
||||||
void DIVDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, false); }
|
|
||||||
void DIVD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, true); }
|
|
||||||
void DIVDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, true); }
|
|
||||||
void DIVDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, false); }
|
|
||||||
void DIVDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, false); }
|
|
||||||
void DIVDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, true); }
|
|
||||||
void DIVDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, true); }
|
|
||||||
void DIVW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, false); }
|
|
||||||
void DIVWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, false); }
|
|
||||||
void DIVW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, true); }
|
|
||||||
void DIVWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, true); }
|
|
||||||
void DIVWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, false); }
|
|
||||||
void DIVWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, false); }
|
|
||||||
void DIVWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, true); }
|
|
||||||
void DIVWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, true); }
|
|
||||||
void ECIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, false); }
|
|
||||||
void ECIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, true); }
|
|
||||||
void ECOWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, false); }
|
|
||||||
void ECOWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, true); }
|
|
||||||
void EIEIO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, false); }
|
|
||||||
void EIEIO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, true); }
|
|
||||||
void EQV(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, false); }
|
|
||||||
void EQV_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, true); }
|
|
||||||
void EXTSB(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, false); }
|
|
||||||
void EXTSB_(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, true); }
|
|
||||||
void EXTSH(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, false); }
|
|
||||||
void EXTSHC(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, false); }
|
|
||||||
void EXTSH_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, true); }
|
|
||||||
void EXTSHC_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, true); }
|
|
||||||
void EXTSW(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, false); }
|
|
||||||
void EXTSW_(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, true); }
|
|
||||||
void FABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, false); }
|
|
||||||
void FABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, true); }
|
|
||||||
void FADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, false); }
|
|
||||||
void FADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, true); }
|
|
||||||
void FADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, false); }
|
|
||||||
void FADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, true); }
|
|
||||||
void FCFID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, false); }
|
|
||||||
void FCFID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, true); }
|
|
||||||
void FCMPO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, false); }
|
|
||||||
void FCMPO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, true); }
|
|
||||||
void FCMPU(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, false); }
|
|
||||||
void FCMPUL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, true); }
|
|
||||||
void FCTID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, false); }
|
|
||||||
void FCTID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, true); }
|
|
||||||
void FCTIDZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, false); }
|
|
||||||
void FCTIDZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, true); }
|
|
||||||
void FCTIW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, false); }
|
|
||||||
void FCTIW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, true); }
|
|
||||||
void FCTIWZ(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, false); }
|
|
||||||
void FCTIWZL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, true); }
|
|
||||||
void FDIV(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, false); }
|
|
||||||
void FDIV_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, true); }
|
|
||||||
void FDIVS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, false); }
|
|
||||||
void FDIVS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, true); }
|
|
||||||
void FMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, false); }
|
|
||||||
void FMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, true); }
|
|
||||||
void FMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, false); }
|
|
||||||
void FMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, true); }
|
|
||||||
void FMR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, false); }
|
|
||||||
void FMR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, true); }
|
|
||||||
void FMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, false); }
|
|
||||||
void FMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, true); }
|
|
||||||
void FMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, false); }
|
|
||||||
void FMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, true); }
|
|
||||||
void FMUL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, false); }
|
|
||||||
void FMUL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, true); }
|
|
||||||
void FMULS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, false); }
|
|
||||||
void FMULS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, true); }
|
|
||||||
void FNABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, false); }
|
|
||||||
void FNABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, true); }
|
|
||||||
void FNEG(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, false); }
|
|
||||||
void FNEG_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, true); }
|
|
||||||
void FNMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, false); }
|
|
||||||
void FNMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, true); }
|
|
||||||
void FNMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, false); }
|
|
||||||
void FNMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, true); }
|
|
||||||
void FNMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, false); }
|
|
||||||
void FNMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, true); }
|
|
||||||
void FNMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, false); }
|
|
||||||
void FNMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, true); }
|
|
||||||
void FRES(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, false); }
|
|
||||||
void FRES_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, true); }
|
|
||||||
void FRSP(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, false); }
|
|
||||||
void FRSP_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, true); }
|
|
||||||
void FRSQRTE(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, false); }
|
|
||||||
void FRSQRTE_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, true); }
|
|
||||||
void FSEL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, false); }
|
|
||||||
void FSEL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, true); }
|
|
||||||
void FSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, false); }
|
|
||||||
void FSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, true); }
|
|
||||||
void FSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, false); }
|
|
||||||
void FSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, true); }
|
|
||||||
void ICBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, false); }
|
|
||||||
void ICBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, true); }
|
|
||||||
void ISYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, false); }
|
|
||||||
void ISYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, true); }
|
|
||||||
void LBZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x88000000, rt, ra, d); }
|
|
||||||
void LBZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x8c000000, rt, ra, d); }
|
|
||||||
void LBZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, false); }
|
|
||||||
void LBZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, true); }
|
|
||||||
void LBZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, false); }
|
|
||||||
void LBZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, true); }
|
|
||||||
void LD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000000, rt, ra, d >> 2); }
|
|
||||||
void LDARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, false); }
|
|
||||||
void LDARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, true); }
|
|
||||||
void LDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000001, rt, ra, d >> 2); }
|
|
||||||
void LDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, false); }
|
|
||||||
void LDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, true); }
|
|
||||||
void LDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, false); }
|
|
||||||
void LDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, true); }
|
|
||||||
void LFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc8000000, rt, ra, d); }
|
|
||||||
void LFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xcc000000, rt, ra, d); }
|
|
||||||
void LFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, false); }
|
|
||||||
void LFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, true); }
|
|
||||||
void LFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, false); }
|
|
||||||
void LFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, true); }
|
|
||||||
void LFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc0000000, rt, ra, d); }
|
|
||||||
void LFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc4000000, rt, ra, d); }
|
|
||||||
void LFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, false); }
|
|
||||||
void LFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, true); }
|
|
||||||
void LFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, false); }
|
|
||||||
void LFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, true); }
|
|
||||||
void LHA(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa8000000, rt, ra, d); }
|
|
||||||
void LHAU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xac000000, rt, ra, d); }
|
|
||||||
void LHAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, false); }
|
|
||||||
void LHAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, true); }
|
|
||||||
void LHAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, false); }
|
|
||||||
void LHAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, true); }
|
|
||||||
void LHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, false); }
|
|
||||||
void LHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, true); }
|
|
||||||
void LHZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa0000000, rt, ra, d); }
|
|
||||||
void LHZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa4000000, rt, ra, d); }
|
|
||||||
void LHZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, false); }
|
|
||||||
void LHZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, true); }
|
|
||||||
void LHZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, false); }
|
|
||||||
void LHZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, true); }
|
|
||||||
void LMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb8000000, rt, ra, d); }
|
|
||||||
void LSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, false); }
|
|
||||||
void LSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, true); }
|
|
||||||
void LSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, false); }
|
|
||||||
void LSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, true); }
|
|
||||||
void LWA(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000002, rt, ra, d >> 2); }
|
|
||||||
void LWARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, false); }
|
|
||||||
void LWARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, true); }
|
|
||||||
void LWAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, false); }
|
|
||||||
void LWAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, true); }
|
|
||||||
void LWAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, false); }
|
|
||||||
void LWAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, true); }
|
|
||||||
void LWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, false); }
|
|
||||||
void LWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, true); }
|
|
||||||
void LWZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x80000000, rt, ra, d); }
|
|
||||||
void LWZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x84000000, rt, ra, d); }
|
|
||||||
void LWZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, false); }
|
|
||||||
void LWZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, true); }
|
|
||||||
void LWZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, false); }
|
|
||||||
void LWZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, true); }
|
|
||||||
void MCRF(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, false); }
|
|
||||||
void MCRFL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, true); }
|
|
||||||
void MCRFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, false); }
|
|
||||||
void MCRFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, true); }
|
|
||||||
void MCRXR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, false); }
|
|
||||||
void MCRXR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, true); }
|
|
||||||
void MFCR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, false); }
|
|
||||||
void MFCR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, true); }
|
|
||||||
void MFFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, false); }
|
|
||||||
void MFFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, true); }
|
|
||||||
void MFMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, false); }
|
|
||||||
void MFMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, true); }
|
|
||||||
void MFSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, false); }
|
|
||||||
void MFSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, true); }
|
|
||||||
void MFSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, false); }
|
|
||||||
void MFSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, true); }
|
|
||||||
void MFSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, false); }
|
|
||||||
void MFSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, true); }
|
|
||||||
void MTCRF(GPR const rt, uint32_t spr) { emit_XFX(0x7c000120, rt, spr); }
|
|
||||||
void MTFSB0(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, false); }
|
|
||||||
void MTFSB0_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, true); }
|
|
||||||
void MTFSB1(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, false); }
|
|
||||||
void MTFSB1_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, true); }
|
|
||||||
void MTFSF() { emit_XFL(0xfc00058e); }
|
|
||||||
void MTFSFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, false); }
|
|
||||||
void MTFSFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, true); }
|
|
||||||
void MTMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, false); }
|
|
||||||
void MTMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, true); }
|
|
||||||
void MTSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, false); }
|
|
||||||
void MTSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, true); }
|
|
||||||
void MTSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, false); }
|
|
||||||
void MTSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, true); }
|
|
||||||
void MTSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, false); }
|
|
||||||
void MTSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, true); }
|
|
||||||
void MULHD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, false); }
|
|
||||||
void MULHDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, false); }
|
|
||||||
void MULHD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, true); }
|
|
||||||
void MULHDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, true); }
|
|
||||||
void MULHDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, false); }
|
|
||||||
void MULHDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, false); }
|
|
||||||
void MULHDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, true); }
|
|
||||||
void MULHDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, true); }
|
|
||||||
void MULHW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, false); }
|
|
||||||
void MULHWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, false); }
|
|
||||||
void MULHW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, true); }
|
|
||||||
void MULHWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, true); }
|
|
||||||
void MULHWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, false); }
|
|
||||||
void MULHWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, false); }
|
|
||||||
void MULHWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, true); }
|
|
||||||
void MULHWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, true); }
|
|
||||||
void MULLD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, false); }
|
|
||||||
void MULLDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, false); }
|
|
||||||
void MULLD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, true); }
|
|
||||||
void MULLDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, true); }
|
|
||||||
void MULLI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x1c000000, rt, ra, d); }
|
|
||||||
void MULLW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, false); }
|
|
||||||
void MULLWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, false); }
|
|
||||||
void MULLW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, true); }
|
|
||||||
void MULLWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, true); }
|
|
||||||
void NAND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, false); }
|
|
||||||
void NAND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, true); }
|
|
||||||
void NEG(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, false); }
|
|
||||||
void NEGO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, false); }
|
|
||||||
void NEG_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, true); }
|
|
||||||
void NEGO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, true); }
|
|
||||||
void NOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, false); }
|
|
||||||
void NOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, true); }
|
|
||||||
void OR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, false); }
|
|
||||||
void OR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, true); }
|
|
||||||
void ORC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, false); }
|
|
||||||
void ORC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, true); }
|
|
||||||
void ORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x60000000, ra, rt, d); }
|
|
||||||
void ORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x64000000, ra, rt, d); }
|
|
||||||
void RFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, false); }
|
|
||||||
void RFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, true); }
|
|
||||||
void RLDCL(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, false); }
|
|
||||||
void RLDCL_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, true); }
|
|
||||||
void RLDCR(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, false); }
|
|
||||||
void RLDCR_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, true); }
|
|
||||||
void RLDIC(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, false); }
|
|
||||||
void RLDIC_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, true); }
|
|
||||||
void RLDICL(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, false); }
|
|
||||||
void RLDICL_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, true); }
|
|
||||||
void RLDICR(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, false); }
|
|
||||||
void RLDICR_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, true); }
|
|
||||||
void RLDIMI(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, false); }
|
|
||||||
void RLDIMI_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, true); }
|
|
||||||
void RLWIMI(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, false); }
|
|
||||||
void RLWIMI_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, true); }
|
|
||||||
void RLWINM(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, false); }
|
|
||||||
void RLWINM_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, true); }
|
|
||||||
void RLWNM(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, false); }
|
|
||||||
void RLWNM_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, true); }
|
|
||||||
void SC(uint32_t lev) { emit_SC(0x44000000, lev); }
|
|
||||||
void SI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
|
||||||
void SI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
|
||||||
void SLBIA(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, false); }
|
|
||||||
void SLBIA_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, true); }
|
|
||||||
void SLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, false); }
|
|
||||||
void SLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, true); }
|
|
||||||
void SLD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, false); }
|
|
||||||
void SLD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, true); }
|
|
||||||
void SLW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, false); }
|
|
||||||
void SLW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, true); }
|
|
||||||
void SRAD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, false); }
|
|
||||||
void SRAD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, true); }
|
|
||||||
void SRADI(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, false); }
|
|
||||||
void SRADI_(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, true); }
|
|
||||||
void SRD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, false); }
|
|
||||||
void SRD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, true); }
|
|
||||||
void SRAW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, false); }
|
|
||||||
void SRAW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, true); }
|
|
||||||
void SRAWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, false); }
|
|
||||||
void SRAWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, true); }
|
|
||||||
void SRW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, false); }
|
|
||||||
void SRW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, true); }
|
|
||||||
void STB(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x98000000, rt, ra, d); }
|
|
||||||
void STBU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x9c000000, rt, ra, d); }
|
|
||||||
void STBUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, false); }
|
|
||||||
void STBUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, true); }
|
|
||||||
void STBX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, false); }
|
|
||||||
void STBX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, true); }
|
|
||||||
void STD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000000, rt, ra, d >> 2); }
|
|
||||||
void STDCX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, false); }
|
|
||||||
void STDCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, true); }
|
|
||||||
void STDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000001, rt, ra, d >> 2); }
|
|
||||||
void STDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, false); }
|
|
||||||
void STDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, true); }
|
|
||||||
void STDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, false); }
|
|
||||||
void STDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, true); }
|
|
||||||
void STFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd8000000, rt, ra, d); }
|
|
||||||
void STFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xdc000000, rt, ra, d); }
|
|
||||||
void STFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, false); }
|
|
||||||
void STFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, true); }
|
|
||||||
void STFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, false); }
|
|
||||||
void STFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, true); }
|
|
||||||
void STFIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, false); }
|
|
||||||
void STFIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, true); }
|
|
||||||
void STFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd0000000, rt, ra, d); }
|
|
||||||
void STFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd4000000, rt, ra, d); }
|
|
||||||
void STFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, false); }
|
|
||||||
void STFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, true); }
|
|
||||||
void STFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, false); }
|
|
||||||
void STFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, true); }
|
|
||||||
void STH(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb0000000, rt, ra, d); }
|
|
||||||
void STHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, false); }
|
|
||||||
void STHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, true); }
|
|
||||||
void STHU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb4000000, rt, ra, d); }
|
|
||||||
void STHUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, false); }
|
|
||||||
void STHUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, true); }
|
|
||||||
void STHX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, false); }
|
|
||||||
void STHX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, true); }
|
|
||||||
void STMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xbc000000, rt, ra, d); }
|
|
||||||
void STSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, false); }
|
|
||||||
void STSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, true); }
|
|
||||||
void STSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, false); }
|
|
||||||
void STSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, true); }
|
|
||||||
void STW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x90000000, rt, ra, d); }
|
|
||||||
void STWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, false); }
|
|
||||||
void STWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, true); }
|
|
||||||
void STWCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, false); }
|
|
||||||
void STWCX__(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, true); }
|
|
||||||
void STWU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x94000000, rt, ra, d); }
|
|
||||||
void STWUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, false); }
|
|
||||||
void STWUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, true); }
|
|
||||||
void STWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, false); }
|
|
||||||
void STWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, true); }
|
|
||||||
void SUBF(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, false); }
|
|
||||||
void SUBFO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, false); }
|
|
||||||
void SUBF_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, true); }
|
|
||||||
void SUBFO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, true); }
|
|
||||||
void SUBFC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, false); }
|
|
||||||
void SUBFCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, false); }
|
|
||||||
void SUBFC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, true); }
|
|
||||||
void SUBFCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, true); }
|
|
||||||
void SUBFE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, false); }
|
|
||||||
void SUBFEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, false); }
|
|
||||||
void SUBFE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, true); }
|
|
||||||
void SUBFEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, true); }
|
|
||||||
void SUBFIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x20000000, rt, ra, d); }
|
|
||||||
void SUBFME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, false); }
|
|
||||||
void SUBFMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, false); }
|
|
||||||
void SUBFME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, true); }
|
|
||||||
void SUBFMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, true); }
|
|
||||||
void SUBFZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, false); }
|
|
||||||
void SUBFZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, false); }
|
|
||||||
void SUBFZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, true); }
|
|
||||||
void SUBFZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, true); }
|
|
||||||
void SYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, false); }
|
|
||||||
void SYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, true); }
|
|
||||||
void TD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, false); }
|
|
||||||
void TD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, true); }
|
|
||||||
void TDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x08000000, rt, ra, d); }
|
|
||||||
void TLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, false); }
|
|
||||||
void TLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, true); }
|
|
||||||
void TLBSYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, false); }
|
|
||||||
void TLBSYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, true); }
|
|
||||||
void TW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, false); }
|
|
||||||
void TW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, true); }
|
|
||||||
void TWI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x0c000000, rt, ra, d); }
|
|
||||||
void XOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, false); }
|
|
||||||
void XOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, true); }
|
|
||||||
void XORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x68000000, ra, rt, d); }
|
|
||||||
void XORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x6c000000, ra, rt, d); }
|
|
||||||
Vendored
-340
@@ -1,340 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include "powah_emit.hpp"
|
|
||||||
|
|
||||||
#define EB32(X) __bswap32(X)
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: addi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.ADDI(powah::R2, powah::R2, 0);
|
|
||||||
ctx.ADDIS(powah::R2, powah::R12, 0);
|
|
||||||
REQUIRE(data[0] == EB32(0x00004238));
|
|
||||||
REQUIRE(data[1] == EB32(0x00004c3c));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: std/mr", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.STD(powah::R26, powah::R1, 144);
|
|
||||||
ctx.MR(powah::R26, powah::R4);
|
|
||||||
ctx.STD(powah::R30, powah::R1, 176);
|
|
||||||
ctx.MR(powah::R30, powah::R3);
|
|
||||||
ctx.RLDICR(powah::R4, powah::R5, 25, 6);
|
|
||||||
ctx.STD(powah::R28, powah::R1, 160);
|
|
||||||
REQUIRE(data[0] == EB32(0x900041fb));
|
|
||||||
REQUIRE(data[1] == EB32(0x78239a7c));
|
|
||||||
REQUIRE(data[2] == EB32(0xb000c1fb));
|
|
||||||
REQUIRE(data[3] == EB32(0x781b7e7c));
|
|
||||||
REQUIRE(data[4] == EB32(0x84c9a478));
|
|
||||||
REQUIRE(data[5] == EB32(0xa00081fb));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: sldi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.SLDI(powah::R3, powah::R5, 37);
|
|
||||||
REQUIRE(data[0] == EB32(0x862ea378));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rldicr", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 0, 0);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 1, 0);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 0, 1);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 1, 1);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 31, 31);
|
|
||||||
REQUIRE(data[0] == EB32(0x04002178));
|
|
||||||
REQUIRE(data[1] == EB32(0x04082178));
|
|
||||||
REQUIRE(data[2] == EB32(0x44002178));
|
|
||||||
REQUIRE(data[3] == EB32(0x44082178));
|
|
||||||
REQUIRE(data[4] == EB32(0xc4ff2178));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: mr/or/std", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.MR(powah::R27, powah::R7);
|
|
||||||
ctx.MR(powah::R29, powah::R6);
|
|
||||||
ctx.OR(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.MR(powah::R4, powah::R28);
|
|
||||||
ctx.CRMOVE(powah::CPR{8}, powah::CPR{1});
|
|
||||||
ctx.MR(powah::R25, powah::R5);
|
|
||||||
ctx.OR(powah::R3, powah::R3, powah::R26);
|
|
||||||
ctx.STD(powah::R3, powah::R1, 56);
|
|
||||||
ctx.MR(powah::R3, powah::R30);
|
|
||||||
REQUIRE(data[0] == EB32(0x783bfb7c));
|
|
||||||
REQUIRE(data[1] == EB32(0x7833dd7c));
|
|
||||||
REQUIRE(data[2] == EB32(0x7823637c));
|
|
||||||
REQUIRE(data[3] == EB32(0x78e3847f));
|
|
||||||
REQUIRE(data[4] == EB32(0x820b014d));
|
|
||||||
REQUIRE(data[5] == EB32(0x782bb97c));
|
|
||||||
REQUIRE(data[6] == EB32(0x78d3637c));
|
|
||||||
REQUIRE(data[7] == EB32(0x380061f8));
|
|
||||||
REQUIRE(data[8] == EB32(0x78f3c37f));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: ld/crand+addi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.LD(powah::R4, powah::R1, 72);
|
|
||||||
ctx.LWZ(powah::R5, powah::R1, 80);
|
|
||||||
ctx.CRAND(powah::CPR{20}, powah::CPR{10}, powah::CPR{9});
|
|
||||||
ctx.ADDI(powah::R6, powah::R4, 4);
|
|
||||||
ctx.ANDIS_(powah::R4, powah::R5, 1992);
|
|
||||||
ctx.LD(powah::R5, powah::R30, 1984);
|
|
||||||
ctx.LBZ(powah::R3, powah::R1, 84);
|
|
||||||
ctx.CLRLDI(powah::R26, powah::R6, 8);
|
|
||||||
ctx.STW(powah::R4, powah::R1, 80);
|
|
||||||
ctx.ADDI(powah::R5, powah::R5, 1);
|
|
||||||
ctx.STD(powah::R26, powah::R1, 72);
|
|
||||||
ctx.STD(powah::R5, powah::R30, 1984);
|
|
||||||
REQUIRE(data[0] == EB32(0x480081e8));
|
|
||||||
REQUIRE(data[1] == EB32(0x5000a180));
|
|
||||||
REQUIRE(data[2] == EB32(0x024a8a4e));
|
|
||||||
REQUIRE(data[3] == EB32(0x0400c438));
|
|
||||||
REQUIRE(data[4] == EB32(0xc807a474));
|
|
||||||
REQUIRE(data[5] == EB32(0xc007bee8));
|
|
||||||
REQUIRE(data[6] == EB32(0x54006188));
|
|
||||||
REQUIRE(data[7] == EB32(0x0002da78));
|
|
||||||
REQUIRE(data[8] == EB32(0x50008190));
|
|
||||||
REQUIRE(data[9] == EB32(0x0100a538));
|
|
||||||
REQUIRE(data[10] == EB32(0x480041fb));
|
|
||||||
REQUIRE(data[11] == EB32(0xc007bef8));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rotldi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 16);
|
|
||||||
ctx.ROTLDI(powah::R4, powah::R3, 8);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 8, 48);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 24);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 16, 40);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 32);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 24, 32);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 48);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 40, 16);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 56);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 48, 8);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R3, 56, 0);
|
|
||||||
ctx.MR(powah::R3, powah::R4);
|
|
||||||
REQUIRE(data[0] == EB32(0x00806578));
|
|
||||||
REQUIRE(data[1] == EB32(0x00406478));
|
|
||||||
REQUIRE(data[2] == EB32(0x2c44a478));
|
|
||||||
REQUIRE(data[3] == EB32(0x00c06578));
|
|
||||||
REQUIRE(data[4] == EB32(0x2c82a478));
|
|
||||||
REQUIRE(data[5] == EB32(0x02006578));
|
|
||||||
REQUIRE(data[6] == EB32(0x2cc0a478));
|
|
||||||
REQUIRE(data[7] == EB32(0x02806578));
|
|
||||||
REQUIRE(data[8] == EB32(0x0e44a478));
|
|
||||||
REQUIRE(data[9] == EB32(0x02c06578));
|
|
||||||
REQUIRE(data[10] == EB32(0x0e82a478));
|
|
||||||
REQUIRE(data[11] == EB32(0x0ec06478));
|
|
||||||
REQUIRE(data[12] == EB32(0x7823837c));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: branch-backwards", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
powah::Label l_3 = ctx.DefineLabel();
|
|
||||||
ctx.LABEL(l_3);
|
|
||||||
ctx.ADD(powah::R1, powah::R2, powah::R3);
|
|
||||||
ctx.B(l_3);
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x141a227c));
|
|
||||||
REQUIRE(data[1] == EB32(0xfcffff4b));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rlwimi madness", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.ROTLWI(powah::R10, powah::R3, 24);
|
|
||||||
ctx.SRDI(powah::R9, powah::R3, 32);
|
|
||||||
ctx.RLWIMI(powah::R10, powah::R3, 8, 8, 15);
|
|
||||||
ctx.RLWIMI(powah::R10, powah::R3, 8, 24, 31);
|
|
||||||
ctx.ROTLWI(powah::R3, powah::R9, 24);
|
|
||||||
ctx.RLWIMI(powah::R3, powah::R9, 8, 8, 15);
|
|
||||||
ctx.RLWIMI(powah::R3, powah::R9, 8, 24, 31);
|
|
||||||
ctx.RLDIMI(powah::R3, powah::R10, 32, 0);
|
|
||||||
REQUIRE(data[0] == EB32(0x3ec06a54));
|
|
||||||
REQUIRE(data[1] == EB32(0x22006978));
|
|
||||||
REQUIRE(data[2] == EB32(0x1e426a50));
|
|
||||||
REQUIRE(data[3] == EB32(0x3e466a50));
|
|
||||||
REQUIRE(data[4] == EB32(0x3ec02355));
|
|
||||||
REQUIRE(data[5] == EB32(0x1e422351));
|
|
||||||
REQUIRE(data[6] == EB32(0x3e462351));
|
|
||||||
REQUIRE(data[7] == EB32(0x0e004379));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
0: 78 1b 68 7c mr 8, 3
|
|
||||||
4: 38 28 83 7c and 3, 4, 5
|
|
||||||
8: 74 00 6a 7c cntlzd 10, 3
|
|
||||||
c: 76 06 69 7c sradi 9, 3, 32
|
|
||||||
10: 82 d1 4a 79 rldicl 10, 10, 58, 6
|
|
||||||
14: 00 00 29 55 rlwinm 9, 9, 0, 0, 0
|
|
||||||
18: 64 f0 4a 79 sldi 10, 10, 30
|
|
||||||
1c: 78 53 29 7d or 9, 9, 10
|
|
||||||
20: 00 00 28 f9 std 9, 0(8)
|
|
||||||
24: 20 00 80 4e blr
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: functor-2", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.MR(powah::R8, powah::R3);
|
|
||||||
ctx.AND(powah::R3, powah::R4, powah::R5);
|
|
||||||
ctx.CNTLZD(powah::R10, powah::R3);
|
|
||||||
ctx.SRADI(powah::R9, powah::R3, 32);
|
|
||||||
ctx.RLDICL(powah::R10, powah::R10, 58, 6);
|
|
||||||
ctx.RLWINM(powah::R9, powah::R9, 0, 0, 0);
|
|
||||||
ctx.SLDI(powah::R10, powah::R10, 30);
|
|
||||||
ctx.OR(powah::R9, powah::R9, powah::R10);
|
|
||||||
ctx.STD(powah::R9, powah::R8, 0);
|
|
||||||
ctx.BLR();
|
|
||||||
REQUIRE(data[0] == EB32(0x781b687c));
|
|
||||||
REQUIRE(data[1] == EB32(0x3828837c));
|
|
||||||
REQUIRE(data[2] == EB32(0x74006a7c));
|
|
||||||
REQUIRE(data[3] == EB32(0x7606697c));
|
|
||||||
REQUIRE(data[4] == EB32(0x82d14a79));
|
|
||||||
REQUIRE(data[5] == EB32(0x00002955));
|
|
||||||
REQUIRE(data[6] == EB32(0x64f04a79));
|
|
||||||
REQUIRE(data[7] == EB32(0x7853297d));
|
|
||||||
REQUIRE(data[8] == EB32(0x000028f9));
|
|
||||||
REQUIRE(data[9] == EB32(0x2000804e));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: functor-1", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
powah::Label l_4 = ctx.DefineLabel();
|
|
||||||
powah::Label l_7 = ctx.DefineLabel();
|
|
||||||
ctx.CMPLD(powah::CR0, powah::R3, powah::R4);
|
|
||||||
ctx.MR(powah::R9, powah::R3);
|
|
||||||
ctx.BGT(powah::CR0, l_7);
|
|
||||||
ctx.CMPLDI(powah::CR0, powah::R3, 3781);
|
|
||||||
ctx.LI(powah::R3, 1);
|
|
||||||
ctx.BGTLR(powah::CR0);
|
|
||||||
ctx.CMPLD(powah::CR0, powah::R9, powah::R5);
|
|
||||||
ctx.BLE(powah::CR0, l_4);
|
|
||||||
ctx.SUBF(powah::R5, powah::R9, powah::R5);
|
|
||||||
ctx.XOR(powah::R3, powah::R5, powah::R4);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.LABEL(l_4);
|
|
||||||
ctx.ADD(powah::R5, powah::R4, powah::R5);
|
|
||||||
ctx.ADD(powah::R3, powah::R5, powah::R9);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.LABEL(l_7);
|
|
||||||
ctx.ADD(powah::R3, powah::R4, powah::R5);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x4020237c));
|
|
||||||
REQUIRE(data[1] == EB32(0x781b697c));
|
|
||||||
REQUIRE(data[2] == EB32(0x30008141));
|
|
||||||
REQUIRE(data[3] == EB32(0xc50e2328));
|
|
||||||
REQUIRE(data[4] == EB32(0x01006038));
|
|
||||||
REQUIRE(data[5] == EB32(0x2000814d));
|
|
||||||
REQUIRE(data[6] == EB32(0x4028297c));
|
|
||||||
REQUIRE(data[7] == EB32(0x10008140));
|
|
||||||
REQUIRE(data[8] == EB32(0x5028a97c));
|
|
||||||
REQUIRE(data[9] == EB32(0x7822a37c));
|
|
||||||
REQUIRE(data[10] == EB32(0x2000804e));
|
|
||||||
REQUIRE(data[11] == EB32(0x142aa47c));
|
|
||||||
REQUIRE(data[12] == EB32(0x144a657c));
|
|
||||||
REQUIRE(data[13] == EB32(0x2000804e));
|
|
||||||
REQUIRE(data[14] == EB32(0x142a647c));
|
|
||||||
REQUIRE(data[15] == EB32(0x2000804e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ARCHITECTURE_powerpc64)
|
|
||||||
/*
|
|
||||||
0: d619637c mullw 3, 3, 3
|
|
||||||
4: 20006378 clrldi 3, 3, 32
|
|
||||||
8: 2000804e blr
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: live-exec square", "[ppc64]") {
|
|
||||||
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
REQUIRE(data != nullptr);
|
|
||||||
|
|
||||||
powah::Context ctx((void*)data, 4096);
|
|
||||||
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
|
||||||
ctx.CLRLDI(powah::R3, powah::R3, 32);
|
|
||||||
ctx.BLR();
|
|
||||||
REQUIRE(data[0] == EB32(0xd619637c));
|
|
||||||
REQUIRE(data[1] == EB32(0x20006378));
|
|
||||||
REQUIRE(data[2] == EB32(0x2000804e));
|
|
||||||
|
|
||||||
auto* fn = (int (*)(int))data;
|
|
||||||
REQUIRE(fn(4) == 4 * 4);
|
|
||||||
REQUIRE(fn(8) == 8 * 8);
|
|
||||||
|
|
||||||
munmap((void*)data, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
int f(int a, int b, int c) {
|
|
||||||
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
|
||||||
return a * a + b ^ c & b;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: live-exec xoralu", "[ppc64]") {
|
|
||||||
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
REQUIRE(data != nullptr);
|
|
||||||
|
|
||||||
powah::Context ctx((void*)data, 4096);
|
|
||||||
powah::Label l_2 = ctx.DefineLabel();
|
|
||||||
powah::Label l_3 = ctx.DefineLabel();
|
|
||||||
ctx.CMPW(powah::R3, powah::R4);
|
|
||||||
ctx.BGT(powah::CR0, l_2);
|
|
||||||
ctx.ADDI(powah::R6, powah::R5, 402);
|
|
||||||
ctx.B(l_3);
|
|
||||||
ctx.LABEL(l_2);
|
|
||||||
ctx.ADDI(powah::R6, powah::R4, 1);
|
|
||||||
ctx.ADDIS(powah::R6, powah::R6, -1);
|
|
||||||
ctx.LABEL(l_3);
|
|
||||||
ctx.ADDI(powah::R4, powah::R4, 2);
|
|
||||||
ctx.ADD(powah::R3, powah::R6, powah::R3);
|
|
||||||
ctx.MULLW(powah::R6, powah::R4, powah::R5);
|
|
||||||
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
|
||||||
ctx.AND(powah::R5, powah::R5, powah::R6);
|
|
||||||
ctx.ADD(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.AND(powah::R4, powah::R5, powah::R4);
|
|
||||||
ctx.XOR(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.EXTSW(powah::R3, powah::R3);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x0020037c));
|
|
||||||
REQUIRE(data[1] == EB32(0x0c008141));
|
|
||||||
REQUIRE(data[2] == EB32(0x9201c538));
|
|
||||||
REQUIRE(data[3] == EB32(0x0c000048));
|
|
||||||
REQUIRE(data[4] == EB32(0x0100c438));
|
|
||||||
REQUIRE(data[5] == EB32(0xffffc63c));
|
|
||||||
REQUIRE(data[6] == EB32(0x02008438));
|
|
||||||
REQUIRE(data[7] == EB32(0x141a667c));
|
|
||||||
REQUIRE(data[8] == EB32(0xd629c47c));
|
|
||||||
REQUIRE(data[9] == EB32(0xd619637c));
|
|
||||||
REQUIRE(data[10] == EB32(0x3830a57c));
|
|
||||||
REQUIRE(data[11] == EB32(0x1422637c));
|
|
||||||
REQUIRE(data[12] == EB32(0x3820a47c));
|
|
||||||
REQUIRE(data[13] == EB32(0x7822637c));
|
|
||||||
REQUIRE(data[14] == EB32(0xb407637c));
|
|
||||||
REQUIRE(data[15] == EB32(0x2000804e));
|
|
||||||
|
|
||||||
auto const orig = [](int a, int b, int c) {
|
|
||||||
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
|
||||||
return a * a + b ^ c & b;
|
|
||||||
};
|
|
||||||
auto* fn = (int (*)(int, int, int))data;
|
|
||||||
REQUIRE(fn(0, 1, 2) == orig(0, 1, 2));
|
|
||||||
REQUIRE(fn(6456, 4564, 4564561) == orig(6456, 4564, 4564561));
|
|
||||||
|
|
||||||
munmap((void*)data, 4096);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64 OR ARCHITECTURE_powerpc64) AND NOT YUZU_STATIC_ROOM)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -14,21 +14,6 @@
|
|||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
|
||||||
// See texture_cache/util.h
|
|
||||||
template<typename T, size_t N>
|
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
|
||||||
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
|
||||||
std::vector<T> u;
|
|
||||||
for (auto const& e : v)
|
|
||||||
u.push_back(e);
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace AudioCore::AudioIn {
|
namespace AudioCore::AudioIn {
|
||||||
|
|
||||||
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
||||||
@@ -110,7 +95,7 @@ Result System::Start() {
|
|||||||
|
|
||||||
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
||||||
buffers.RegisterBuffers(buffers_to_flush);
|
buffers.RegisterBuffers(buffers_to_flush);
|
||||||
session->AppendBuffers(FixStaticVectorADL(buffers_to_flush));
|
session->AppendBuffers(buffers_to_flush);
|
||||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@@ -155,7 +140,7 @@ void System::RegisterBuffers() {
|
|||||||
if (state == State::Started) {
|
if (state == State::Started) {
|
||||||
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
||||||
buffers.RegisterBuffers(registered_buffers);
|
buffers.RegisterBuffers(registered_buffers);
|
||||||
session->AppendBuffers(FixStaticVectorADL(registered_buffers));
|
session->AppendBuffers(registered_buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1241,7 +1241,7 @@ if (HAS_NCE)
|
|||||||
target_link_libraries(core PRIVATE merry::oaknut)
|
target_link_libraries(core PRIVATE merry::oaknut)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_powerpc64 OR ARCHITECTURE_powerpc64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_64.cpp
|
arm/dynarmic/arm_dynarmic_64.cpp
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ add_library(dynarmic STATIC
|
|||||||
interface/halt_reason.h
|
interface/halt_reason.h
|
||||||
interface/exclusive_monitor.h
|
interface/exclusive_monitor.h
|
||||||
interface/optimization_flags.h
|
interface/optimization_flags.h
|
||||||
interface/halt_reason.h
|
|
||||||
ir/acc_type.h
|
ir/acc_type.h
|
||||||
ir/basic_block.cpp
|
ir/basic_block.cpp
|
||||||
ir/basic_block.h
|
ir/basic_block.h
|
||||||
@@ -140,8 +139,10 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
|||||||
# Newer versions of xbyak (>= 7.25.0) have stricter checks that currently
|
# Newer versions of xbyak (>= 7.25.0) have stricter checks that currently
|
||||||
# fail in dynarmic
|
# fail in dynarmic
|
||||||
target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0)
|
target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0)
|
||||||
|
|
||||||
target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1)
|
target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1)
|
||||||
target_link_libraries(dynarmic PRIVATE xbyak::xbyak)
|
target_link_libraries(dynarmic PRIVATE xbyak::xbyak)
|
||||||
|
|
||||||
target_architecture_specific_sources(dynarmic "x86_64"
|
target_architecture_specific_sources(dynarmic "x86_64"
|
||||||
backend/x64/abi.cpp
|
backend/x64/abi.cpp
|
||||||
backend/x64/abi.h
|
backend/x64/abi.h
|
||||||
@@ -293,35 +294,6 @@ if ("riscv64" IN_LIST ARCHITECTURE)
|
|||||||
)
|
)
|
||||||
message(WARNING "TODO: Incomplete frontend for this host architecture")
|
message(WARNING "TODO: Incomplete frontend for this host architecture")
|
||||||
endif()
|
endif()
|
||||||
if ("powerpc64" IN_LIST ARCHITECTURE)
|
|
||||||
target_link_libraries(dynarmic PRIVATE powah)
|
|
||||||
target_sources(dynarmic PRIVATE
|
|
||||||
backend/ppc64/abi.h
|
|
||||||
backend/ppc64/emit_context.h
|
|
||||||
backend/ppc64/emit_ppc64_a32.cpp
|
|
||||||
backend/ppc64/emit_ppc64_a64.cpp
|
|
||||||
backend/ppc64/emit_ppc64_misc.cpp
|
|
||||||
backend/ppc64/emit_ppc64_data_processing.cpp
|
|
||||||
backend/ppc64/emit_ppc64_floating_point.cpp
|
|
||||||
backend/ppc64/emit_ppc64_vector.cpp
|
|
||||||
backend/ppc64/emit_ppc64.cpp
|
|
||||||
backend/ppc64/emit_ppc64.h
|
|
||||||
backend/ppc64/exclusive_monitor.cpp
|
|
||||||
backend/ppc64/reg_alloc.cpp
|
|
||||||
backend/ppc64/reg_alloc.h
|
|
||||||
backend/ppc64/stack_layout.h
|
|
||||||
backend/ppc64/hostloc.h
|
|
||||||
common/spin_lock_ppc64.cpp
|
|
||||||
common/spin_lock_ppc64.h
|
|
||||||
# A32
|
|
||||||
backend/ppc64/a32_core.h
|
|
||||||
backend/ppc64/a32_interface.cpp
|
|
||||||
# A64
|
|
||||||
backend/ppc64/a64_core.h
|
|
||||||
backend/ppc64/a64_interface.cpp
|
|
||||||
backend/ppc64/code_block.h
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ("loongarch64" IN_LIST ARCHITECTURE)
|
if ("loongarch64" IN_LIST ARCHITECTURE)
|
||||||
target_link_libraries(dynarmic PRIVATE lagoon::lagoon)
|
target_link_libraries(dynarmic PRIVATE lagoon::lagoon)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend::X64 {
|
||||||
class BlockOfCode;
|
class BlockOfCode;
|
||||||
}
|
} // namespace Dynarmic::Backend::X64
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#elif defined(ARCHITECTURE_arm64)
|
||||||
namespace oaknut {
|
namespace oaknut {
|
||||||
class CodeBlock;
|
class CodeBlock;
|
||||||
@@ -30,10 +30,6 @@ class CodeBlock;
|
|||||||
namespace Dynarmic::Backend::LoongArch64 {
|
namespace Dynarmic::Backend::LoongArch64 {
|
||||||
class CodeBlock;
|
class CodeBlock;
|
||||||
} // namespace Dynarmic::Backend::LoongArch64
|
} // namespace Dynarmic::Backend::LoongArch64
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
class CodeBlock;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -57,9 +53,6 @@ struct FakeCall {
|
|||||||
struct FakeCall {
|
struct FakeCall {
|
||||||
u64 call_pc;
|
u64 call_pc;
|
||||||
};
|
};
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
struct FakeCall {
|
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -77,8 +70,6 @@ public:
|
|||||||
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
|
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
void Register(LoongArch64::CodeBlock& mem, std::size_t mem_size);
|
void Register(LoongArch64::CodeBlock& mem, std::size_t mem_size);
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
void Register(PPC64::CodeBlock& mem, std::size_t mem_size);
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,21 +17,24 @@ ExceptionHandler::ExceptionHandler() = default;
|
|||||||
ExceptionHandler::~ExceptionHandler() = default;
|
ExceptionHandler::~ExceptionHandler() = default;
|
||||||
|
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
void ExceptionHandler::Register(X64::BlockOfCode&)
|
void ExceptionHandler::Register(X64::BlockOfCode&) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#elif defined(ARCHITECTURE_arm64)
|
||||||
void ExceptionHandler::Register(oaknut::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(oaknut::CodeBlock&, std::size_t) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_riscv64)
|
#elif defined(ARCHITECTURE_riscv64)
|
||||||
void ExceptionHandler::Register(RV64::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(RV64::CodeBlock&, std::size_t) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
void ExceptionHandler::Register(LoongArch64::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(LoongArch64::CodeBlock&, std::size_t) {
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
// Do nothing
|
||||||
void ExceptionHandler::Register(PPC64::CodeBlock&, std::size_t)
|
}
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -36,8 +35,6 @@
|
|||||||
# include "dynarmic/backend/riscv64/code_block.h"
|
# include "dynarmic/backend/riscv64/code_block.h"
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
# include "dynarmic/backend/loongarch64/code_block.h"
|
# include "dynarmic/backend/loongarch64/code_block.h"
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
# include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -208,10 +205,6 @@ void ExceptionHandler::Register(RV64::CodeBlock& mem, std::size_t size) {
|
|||||||
void ExceptionHandler::Register(LoongArch64::CodeBlock& mem, std::size_t size) {
|
void ExceptionHandler::Register(LoongArch64::CodeBlock& mem, std::size_t size) {
|
||||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
||||||
}
|
}
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
void ExceptionHandler::Register(PPC64::CodeBlock& mem, std::size_t size) {
|
|
||||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
|
||||||
#include "dynarmic/interface/A32/config.h"
|
|
||||||
#include "dynarmic/ir/terminal.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct A32JitState {
|
|
||||||
std::array<u32, 16> regs{};
|
|
||||||
alignas(16) std::array<u32, 64> ext_regs{};
|
|
||||||
u32 upper_location_descriptor;
|
|
||||||
u32 exclusive_state = 0;
|
|
||||||
u32 cpsr_nzcv = 0;
|
|
||||||
u32 fpscr = 0;
|
|
||||||
u32 check_bit = 0;
|
|
||||||
|
|
||||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
|
||||||
return IR::LocationDescriptor{regs[15] | (u64(upper_location_descriptor) << 32)};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
|
||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
|
||||||
#include "dynarmic/interface/A32/config.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/common/atomic.h"
|
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
using namespace Dynarmic::Backend::PPC64;
|
|
||||||
using CodePtr = std::uint32_t*;
|
|
||||||
|
|
||||||
struct A32AddressSpace final {
|
|
||||||
explicit A32AddressSpace(const A32::UserConfig& conf)
|
|
||||||
: conf(conf)
|
|
||||||
, cb(conf.code_cache_size)
|
|
||||||
, as(cb.ptr<u8*>(), conf.code_cache_size) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CodePtr GetOrEmit(IR::LocationDescriptor desc) {
|
|
||||||
if (auto const it = block_entries.find(desc.Value()); it != block_entries.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
ir_block.Reset(A32::LocationDescriptor{desc});
|
|
||||||
A32::Translate(ir_block, A32::LocationDescriptor{desc}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
|
||||||
|
|
||||||
block_infos.insert_or_assign(desc.Value(), block_info);
|
|
||||||
block_entries.insert_or_assign(desc.Value(), block_info.entry_point);
|
|
||||||
return block_info.entry_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
block_entries.clear();
|
|
||||||
block_infos.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo Emit(IR::Block block) {
|
|
||||||
EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), {
|
|
||||||
.enable_cycle_counting = conf.enable_cycle_counting,
|
|
||||||
.always_little_endian = conf.always_little_endian,
|
|
||||||
.a64_variant = false
|
|
||||||
});
|
|
||||||
Link(block_info);
|
|
||||||
return block_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link(EmittedBlockInfo& block_info) {
|
|
||||||
//UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)};
|
|
||||||
const A32::UserConfig conf;
|
|
||||||
CodeBlock cb;
|
|
||||||
powah::Context as;
|
|
||||||
ankerl::unordered_dense::map<u64, CodePtr> block_entries;
|
|
||||||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> block_infos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct A32Core final {
|
|
||||||
static HaltReason Run(A32AddressSpace& process, A32JitState& thread_ctx, volatile u32* halt_reason) {
|
|
||||||
auto const loc = thread_ctx.GetLocationDescriptor();
|
|
||||||
auto const entry = process.GetOrEmit(loc);
|
|
||||||
using CodeFn = HaltReason (*)(A32AddressSpace*, A32JitState*, volatile u32*, void*);
|
|
||||||
return (CodeFn(entry))(&process, &thread_ctx, halt_reason, reinterpret_cast<void*>(&A32Core::Run));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Jit::Impl final {
|
|
||||||
Impl(Jit* jit_interface, A32::UserConfig conf)
|
|
||||||
: conf(conf)
|
|
||||||
, current_address_space(conf)
|
|
||||||
, jit_interface(jit_interface) {}
|
|
||||||
|
|
||||||
HaltReason Run() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
is_executing = false;
|
|
||||||
HaltReason hr = A32Core::Run(current_address_space, jit_state, &halt_reason);
|
|
||||||
is_executing = true;
|
|
||||||
RequestCacheInvalidation();
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Step() {
|
|
||||||
// HaltReason hr = A32Core::Step(current_address_space, jit_state, &halt_reason);
|
|
||||||
// RequestCacheInvalidation();
|
|
||||||
return HaltReason{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateCacheRange(u32 start_address, size_t length) {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, u32(start_address + length - 1)));
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
jit_state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
|
||||||
Atomic::Or(&halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
|
||||||
Atomic::And(&halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 16>& Regs() {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 16>& Regs() const {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 64>& ExtRegs() {
|
|
||||||
return jit_state.ext_regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 64>& ExtRegs() const {
|
|
||||||
return jit_state.ext_regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Cpsr() const {
|
|
||||||
return jit_state.cpsr_nzcv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCpsr(u32 value) {
|
|
||||||
jit_state.cpsr_nzcv = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Fpscr() const {
|
|
||||||
return jit_state.fpscr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpscr(u32 value) {
|
|
||||||
jit_state.fpscr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
|
||||||
jit_state.exclusive_state = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RequestCacheInvalidation() {
|
|
||||||
// UNREACHABLE();
|
|
||||||
invalidate_entire_cache = false;
|
|
||||||
invalid_cache_ranges.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
A32::UserConfig conf;
|
|
||||||
A32JitState jit_state{};
|
|
||||||
A32AddressSpace current_address_space;
|
|
||||||
Jit* jit_interface;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
bool is_executing = false;
|
|
||||||
|
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Impl>(this, conf)) {}
|
|
||||||
Jit::~Jit() = default;
|
|
||||||
|
|
||||||
HaltReason Jit::Run() {
|
|
||||||
return impl->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Jit::Step() {
|
|
||||||
return impl->Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
|
||||||
impl->ClearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
|
||||||
impl->InvalidateCacheRange(start_address, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::Reset() {
|
|
||||||
impl->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::HaltExecution(HaltReason hr) {
|
|
||||||
impl->HaltExecution(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearHalt(HaltReason hr) {
|
|
||||||
impl->ClearHalt(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 16>& Jit::Regs() {
|
|
||||||
return impl->Regs();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 16>& Jit::Regs() const {
|
|
||||||
return impl->Regs();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 64>& Jit::ExtRegs() {
|
|
||||||
return impl->ExtRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 64>& Jit::ExtRegs() const {
|
|
||||||
return impl->ExtRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::Cpsr() const {
|
|
||||||
return impl->Cpsr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetCpsr(u32 value) {
|
|
||||||
impl->SetCpsr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::Fpscr() const {
|
|
||||||
return impl->Fpscr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpscr(u32 value) {
|
|
||||||
impl->SetFpscr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearExclusiveState() {
|
|
||||||
impl->ClearExclusiveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
#include "dynarmic/ir/terminal.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct A64JitState {
|
|
||||||
using ProgramCounterType = u32;
|
|
||||||
std::array<u64, 31> regs{};
|
|
||||||
u64 pc = 0;
|
|
||||||
alignas(16) std::array<u64, 64> vec{};
|
|
||||||
u64 sp = 0;
|
|
||||||
u32 upper_location_descriptor = 0;
|
|
||||||
u32 exclusive_state = 0;
|
|
||||||
u32 pstate = 0;
|
|
||||||
u32 fpcr = 0;
|
|
||||||
u32 fpsr = 0;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
u32 check_bit = 0;
|
|
||||||
|
|
||||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
|
||||||
const u64 fpcr_u64 = u64(fpcr & A64::LocationDescriptor::fpcr_mask) << A64::LocationDescriptor::fpcr_shift;
|
|
||||||
const u64 pc_u64 = pc & A64::LocationDescriptor::pc_mask;
|
|
||||||
return IR::LocationDescriptor{pc_u64 | fpcr_u64};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/common/atomic.h"
|
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A64 {
|
|
||||||
|
|
||||||
using namespace Dynarmic::Backend::PPC64;
|
|
||||||
using CodePtr = std::uint32_t*;
|
|
||||||
|
|
||||||
struct A64AddressSpace final {
|
|
||||||
explicit A64AddressSpace(const A64::UserConfig& conf)
|
|
||||||
: conf(conf)
|
|
||||||
, cb(conf.code_cache_size)
|
|
||||||
, as(cb.ptr<u8*>(), conf.code_cache_size)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CodePtr GetOrEmit(IR::LocationDescriptor desc) {
|
|
||||||
if (auto const it = block_entries.find(desc.Value()); it != block_entries.end())
|
|
||||||
return it->second;
|
|
||||||
auto const get_code = [this](u64 vaddr) {
|
|
||||||
return conf.callbacks->MemoryReadCode(vaddr);
|
|
||||||
};
|
|
||||||
ir_block.Reset(A64::LocationDescriptor{desc});
|
|
||||||
A64::Translate(ir_block, A64::LocationDescriptor{desc}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
|
||||||
fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block));
|
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
|
||||||
block_infos.insert_or_assign(desc.Value(), block_info);
|
|
||||||
block_entries.insert_or_assign(desc.Value(), block_info.entry_point);
|
|
||||||
return block_info.entry_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
block_entries.clear();
|
|
||||||
block_infos.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo Emit(IR::Block block) {
|
|
||||||
EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), {
|
|
||||||
.enable_cycle_counting = conf.enable_cycle_counting,
|
|
||||||
.always_little_endian = true,
|
|
||||||
.a64_variant = true
|
|
||||||
});
|
|
||||||
Link(block_info);
|
|
||||||
return block_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link(EmittedBlockInfo& block_info) {
|
|
||||||
// TODO(lizzie): Block linking
|
|
||||||
// UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)};
|
|
||||||
const A64::UserConfig conf;
|
|
||||||
CodeBlock cb;
|
|
||||||
powah::Context as;
|
|
||||||
ankerl::unordered_dense::map<u64, CodePtr> block_entries;
|
|
||||||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> block_infos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct A64Core final {
|
|
||||||
using CodeFn = HaltReason (*)(A64AddressSpace*, A64JitState*, volatile u32*, void *fn);
|
|
||||||
static HaltReason Run(A64AddressSpace& process, A64JitState& thread_ctx, volatile u32* halt_reason) {
|
|
||||||
HaltReason hr{};
|
|
||||||
do {
|
|
||||||
const auto loc = thread_ctx.GetLocationDescriptor();
|
|
||||||
const auto entry = process.GetOrEmit(loc);
|
|
||||||
hr = (CodeFn(entry))(&process, &thread_ctx, halt_reason, (void*)&A64Core::Run);
|
|
||||||
} while (hr == HaltReason(0));
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Jit::Impl final {
|
|
||||||
Impl(Jit* jit_interface, A64::UserConfig conf)
|
|
||||||
: conf(conf)
|
|
||||||
, current_address_space(conf)
|
|
||||||
, jit_interface(jit_interface) {}
|
|
||||||
|
|
||||||
HaltReason Run() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
is_executing = true;
|
|
||||||
HaltReason hr = A64Core::Run(current_address_space, jit_state, &halt_reason);
|
|
||||||
is_executing = false;
|
|
||||||
RequestCacheInvalidation();
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Step() {
|
|
||||||
// HaltReason hr = A64Core::Step(current_address_space, jit_state, &halt_reason);
|
|
||||||
// RequestCacheInvalidation();
|
|
||||||
return HaltReason{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateCacheRange(u64 start_address, size_t length) {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
const auto end_address = u64(start_address + length - 1);
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u64>::closed(start_address, end_address));
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
jit_state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
|
||||||
Atomic::Or(&jit_state.halt_reason, u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
|
||||||
Atomic::And(&jit_state.halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetSP() const {
|
|
||||||
return jit_state.sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSP(u64 value) {
|
|
||||||
jit_state.sp = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetPC() const {
|
|
||||||
return jit_state.pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPC(u64 value) {
|
|
||||||
jit_state.pc = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetRegister(size_t index) const {
|
|
||||||
return index == 31 ? GetSP() : jit_state.regs.at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRegister(size_t index, u64 value) {
|
|
||||||
if (index == 31)
|
|
||||||
return SetSP(value);
|
|
||||||
jit_state.regs.at(index) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, 31> GetRegisters() const {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRegisters(const std::array<u64, 31>& value) {
|
|
||||||
jit_state.regs = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector GetVector(size_t index) const {
|
|
||||||
return {jit_state.vec.at(index * 2), jit_state.vec.at(index * 2 + 1)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVector(size_t index, Vector value) {
|
|
||||||
jit_state.vec.at(index * 2) = value[0];
|
|
||||||
jit_state.vec.at(index * 2 + 1) = value[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Vector, 32> GetVectors() const {
|
|
||||||
std::array<Vector, 32> ret;
|
|
||||||
static_assert(sizeof(ret) == sizeof(jit_state.vec));
|
|
||||||
std::memcpy(ret.data(), jit_state.vec.data(), sizeof(jit_state.vec));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVectors(const std::array<Vector, 32>& value) {
|
|
||||||
static_assert(sizeof(value) == sizeof(jit_state.vec));
|
|
||||||
std::memcpy(jit_state.vec.data(), value.data(), sizeof(jit_state.vec));
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFpcr() const {
|
|
||||||
return jit_state.fpcr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpcr(u32 value) {
|
|
||||||
jit_state.fpcr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFpsr() const {
|
|
||||||
return jit_state.fpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpsr(u32 value) {
|
|
||||||
jit_state.fpsr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetPstate() const {
|
|
||||||
return jit_state.pstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPstate(u32 value) {
|
|
||||||
jit_state.pstate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
|
||||||
jit_state.exclusive_state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsExecuting() const {
|
|
||||||
return is_executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Disassemble() const {
|
|
||||||
// const size_t size = reinterpret_cast<const char*>(block_of_code.getCurr()) - reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
|
||||||
// auto const* p = reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
|
||||||
// return Common::DisassemblePPC64(p, p + size);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RequestCacheInvalidation() {
|
|
||||||
// UNREACHABLE();
|
|
||||||
invalidate_entire_cache = false;
|
|
||||||
invalid_cache_ranges.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
A64::UserConfig conf;
|
|
||||||
A64JitState jit_state{};
|
|
||||||
A64AddressSpace current_address_space;
|
|
||||||
Jit* jit_interface;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
bool is_executing = false;
|
|
||||||
|
|
||||||
boost::icl::interval_set<u64> invalid_cache_ranges;
|
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Jit::Impl>(this, conf)) {}
|
|
||||||
Jit::~Jit() = default;
|
|
||||||
|
|
||||||
HaltReason Jit::Run() {
|
|
||||||
return impl->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Jit::Step() {
|
|
||||||
return impl->Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
|
||||||
impl->ClearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::InvalidateCacheRange(u64 start_address, size_t length) {
|
|
||||||
impl->InvalidateCacheRange(start_address, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::Reset() {
|
|
||||||
impl->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::HaltExecution(HaltReason hr) {
|
|
||||||
impl->HaltExecution(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearHalt(HaltReason hr) {
|
|
||||||
impl->ClearHalt(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetSP() const {
|
|
||||||
return impl->GetSP();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetSP(u64 value) {
|
|
||||||
impl->SetSP(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetPC() const {
|
|
||||||
return impl->GetPC();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetPC(u64 value) {
|
|
||||||
impl->SetPC(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetRegister(size_t index) const {
|
|
||||||
return impl->GetRegister(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetRegister(size_t index, u64 value) {
|
|
||||||
impl->SetRegister(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, 31> Jit::GetRegisters() const {
|
|
||||||
return impl->GetRegisters();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetRegisters(const std::array<u64, 31>& value) {
|
|
||||||
impl->SetRegisters(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector Jit::GetVector(size_t index) const {
|
|
||||||
return impl->GetVector(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetVector(size_t index, Vector value) {
|
|
||||||
impl->SetVector(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Vector, 32> Jit::GetVectors() const {
|
|
||||||
return impl->GetVectors();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetVectors(const std::array<Vector, 32>& value) {
|
|
||||||
impl->SetVectors(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetFpcr() const {
|
|
||||||
return impl->GetFpcr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpcr(u32 value) {
|
|
||||||
impl->SetFpcr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetFpsr() const {
|
|
||||||
return impl->GetFpsr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpsr(u32 value) {
|
|
||||||
impl->SetFpsr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetPstate() const {
|
|
||||||
return impl->GetPstate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetPstate(u32 value) {
|
|
||||||
impl->SetPstate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearExclusiveState() {
|
|
||||||
impl->ClearExclusiveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Jit::IsExecuting() const {
|
|
||||||
return impl->IsExecuting();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Jit::Disassemble() const {
|
|
||||||
return impl->Disassemble();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
/*
|
|
||||||
https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#REG
|
|
||||||
|
|
||||||
r0 Volatile register used in function prologs
|
|
||||||
r1 Stack frame pointer
|
|
||||||
r2 TOC pointer
|
|
||||||
r3 Volatile parameter and return value register
|
|
||||||
r4-r10 Volatile registers used for function parameters
|
|
||||||
r11 Volatile register used in calls by pointer and as an environment pointer for languages which require one
|
|
||||||
r12 Volatile register used for exception handling and glink code
|
|
||||||
r13 Reserved for use as system thread ID
|
|
||||||
r14-r31 Nonvolatile registers used for local variables
|
|
||||||
|
|
||||||
f0 Volatile scratch register
|
|
||||||
f1-f4 Volatile floating point parameter and return value registers
|
|
||||||
f5-f13 Volatile floating point parameter registers
|
|
||||||
f14-f31 Nonvolatile registers
|
|
||||||
|
|
||||||
LR Link register (volatile)
|
|
||||||
CTR Loop counter register (volatile)
|
|
||||||
XER Fixed point exception register (volatile)
|
|
||||||
FPSCR Floating point status and control register (volatile)
|
|
||||||
|
|
||||||
CR0-CR1 Volatile condition code register fields
|
|
||||||
CR2-CR4 Nonvolatile condition code register fields
|
|
||||||
CR5-CR7 Volatile condition code register fields
|
|
||||||
|
|
||||||
v0-v1 Volatile scratch registers
|
|
||||||
v2-v13 Volatile vector parameters registers
|
|
||||||
v14-v19 Volatile scratch registers
|
|
||||||
v20-v31 Non-volatile registers
|
|
||||||
vrsave Non-volatile 32-bit register
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Jit fn signature => (AXXAddressSpace& process, AXXJitState& thread_ctx, volatile u32* halt_reason)
|
|
||||||
constexpr powah::GPR RPROCESS = powah::R3;
|
|
||||||
constexpr powah::GPR RJIT = powah::R4;
|
|
||||||
constexpr powah::GPR RHALTREASON = powah::R5;
|
|
||||||
constexpr powah::GPR RTOCPTR = powah::R6;
|
|
||||||
// temporals
|
|
||||||
constexpr powah::GPR RNZCV = powah::R7;
|
|
||||||
|
|
||||||
constexpr powah::GPR ABI_PARAM1 = powah::R3;
|
|
||||||
constexpr powah::GPR ABI_PARAM2 = powah::R4;
|
|
||||||
constexpr powah::GPR ABI_PARAM3 = powah::R5;
|
|
||||||
constexpr powah::GPR ABI_PARAM4 = powah::R6;
|
|
||||||
|
|
||||||
// See https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#REG
|
|
||||||
constexpr std::initializer_list<u32> GPR_ORDER{
|
|
||||||
// r13 is thread-id
|
|
||||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 //non-volatile
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::initializer_list<powah::GPR> ABI_CALLEER_SAVED{
|
|
||||||
powah::R3, powah::R4, powah::R5, powah::R6,
|
|
||||||
powah::R7, powah::R8, powah::R9, powah::R10,
|
|
||||||
powah::R11, powah::R12
|
|
||||||
};
|
|
||||||
constexpr std::initializer_list<powah::GPR> ABI_CALLEE_SAVED{
|
|
||||||
powah::R14, powah::R15, powah::R16, powah::R17,
|
|
||||||
powah::R18, powah::R19, powah::R20, powah::R21,
|
|
||||||
powah::R22, powah::R23, powah::R24, powah::R25,
|
|
||||||
powah::R26, powah::R27, powah::R28, powah::R29,
|
|
||||||
powah::R30, powah::R31
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <new>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
class CodeBlock {
|
|
||||||
public:
|
|
||||||
explicit CodeBlock(size_t size_) noexcept : size{size_} {
|
|
||||||
block = (u8*)mmap(nullptr, size, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
//printf("block = %p, size= %zx\n", block, size);
|
|
||||||
ASSERT(block != nullptr);
|
|
||||||
}
|
|
||||||
~CodeBlock() noexcept {
|
|
||||||
if (block != nullptr)
|
|
||||||
munmap(block, size);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
T ptr() const noexcept {
|
|
||||||
static_assert(std::is_pointer_v<T> || std::is_same_v<T, uintptr_t> || std::is_same_v<T, intptr_t>);
|
|
||||||
return reinterpret_cast<T>(block);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
void* block = nullptr;
|
|
||||||
size_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
|
||||||
class Block;
|
|
||||||
} // namespace Dynarmic::IR
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct EmitConfig;
|
|
||||||
|
|
||||||
struct EmitContext {
|
|
||||||
IR::Block& block;
|
|
||||||
RegAlloc& reg_alloc;
|
|
||||||
const EmitConfig& emit_conf;
|
|
||||||
EmittedBlockInfo& ebi;
|
|
||||||
// label used when returning :)
|
|
||||||
powah::Label l_return;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/backend/ppc64/stack_layout.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
#include "stack_layout.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Void>(powah::Context&, EmitContext&, IR::Inst*) {}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Identity>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.MR(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Breakpoint>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CallHostFunction>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PushRSB>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetCarryFromOp>(powah::Context&, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetOverflowFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetGEFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetNZCVFromOp>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (ctx.reg_alloc.IsValueLive(inst)) {
|
|
||||||
ASSERT(false && "unimp value live");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All logical operations whom set (RC) are going to compute as the following:
|
|
||||||
// 1. Rt <- logical_op (Ra, Rb)
|
|
||||||
// 2. Compare as Signed(Rt) against 0
|
|
||||||
// Basically, it's equivalent to say:
|
|
||||||
//
|
|
||||||
// add r0, r1, r2 -> add. r0, r1, r2
|
|
||||||
// cmpli r0, 0
|
|
||||||
//
|
|
||||||
// CR0:
|
|
||||||
// 0 - 0x08 - N/LT, result is negative
|
|
||||||
// 1 - 0x04 - P/GT, result is positive
|
|
||||||
// 2 - 0x02 - Z/EQ, result is zero
|
|
||||||
// 3 - 0x01 - S/SO, summary overflow (carry?)
|
|
||||||
// XER:
|
|
||||||
// 32 - SO
|
|
||||||
// 33 - Overflow
|
|
||||||
// 34 - Carry
|
|
||||||
// NZCV -> (CR0.0, CR0.2, XER.34, XER.33)
|
|
||||||
if (false) {
|
|
||||||
//code.MFSPR(powah::GPR{1}, tmp4, powah::R0); // From XER
|
|
||||||
/*uint64_t nzcv(uint64_t cr0, uint64_t xer) {
|
|
||||||
return ((xer >> 33) & 1)
|
|
||||||
| (((xer >> 34) & 1) << 1)
|
|
||||||
| (((cr0 >> (32 + 2)) & 1) << 2)
|
|
||||||
| (((cr0 >> (32 + 0)) & 1) << 3);
|
|
||||||
}*/
|
|
||||||
// auto const tmp9 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// code.SRDI(tmp9, tmp3, 34);
|
|
||||||
// code.RLDICL(tmp10, tmp4, 31, 63);
|
|
||||||
// code.SRDI(tmp3, tmp3, 32);
|
|
||||||
// code.RLDIC(tmp9, tmp9, 2, 61);
|
|
||||||
// code.OR(tmp9, tmp9, tmp10);
|
|
||||||
// code.RLDIC(tmp3, tmp3, 3, 60);
|
|
||||||
// code.SRDI(tmp4, tmp4, 34);
|
|
||||||
// code.OR(tmp3, tmp9, tmp3);
|
|
||||||
// code.RLDIC(tmp4, tmp4, 1, 62);
|
|
||||||
// code.OR(tmp3, tmp3, tmp4);
|
|
||||||
} else {
|
|
||||||
// MFCR Fills RT 32:63, RT 0:31 left blank
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.MR(tmp3, PPC64::RNZCV);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetNZFromOp>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetUpperFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetLowerFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetCFlagFromNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::NZCVFromPackedFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void EmitLeafTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// r3 -> process
|
|
||||||
// r4 -> thread_ctx
|
|
||||||
// r5 -> halt_reason
|
|
||||||
// r6 -> test_thunk
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool) {
|
|
||||||
if (ctx.emit_conf.a64_variant) {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LI(tmp, terminal.next.Value());
|
|
||||||
code.STD(tmp, PPC64::RJIT, offsetof(A64JitState, pc));
|
|
||||||
code.B(ctx.l_return);
|
|
||||||
} else {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LI(tmp, terminal.next.Value());
|
|
||||||
code.STW(tmp, PPC64::RJIT, offsetof(A32JitState, regs) + sizeof(u32) * 15);
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
EmitTerminal(code, ctx, IR::Term::LinkBlock{terminal.next}, initial_location, is_single_step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::PopRSBHint, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
powah::Label const l_else = code.DefineLabel();
|
|
||||||
powah::Label const l_end = code.DefineLabel();
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(tmp, PPC64::RJIT, offsetof(A64JitState, check_bit));
|
|
||||||
code.CMPLDI(tmp, 0);
|
|
||||||
code.BEQ(powah::CR0, l_else);
|
|
||||||
// CheckBit == 1
|
|
||||||
EmitLeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
|
|
||||||
code.B(l_end);
|
|
||||||
// CheckBit == 0
|
|
||||||
code.LABEL(l_else);
|
|
||||||
EmitLeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
|
|
||||||
code.LABEL(l_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitLeafTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
|
|
||||||
return EmitLeafTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::If>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConfig& emit_conf) {
|
|
||||||
EmittedBlockInfo ebi;
|
|
||||||
RegAlloc reg_alloc{code};
|
|
||||||
EmitContext ctx{block, reg_alloc, emit_conf, ebi, code.DefineLabel()};
|
|
||||||
size_t const stack_size = 112 + ABI_CALLEE_SAVED.size() * 8;
|
|
||||||
auto const start_offset = code.offset;
|
|
||||||
ebi.entry_point = &code.base[start_offset];
|
|
||||||
if (!block.instructions.empty()) {
|
|
||||||
code.MFLR(powah::R0);
|
|
||||||
code.STD(powah::R0, powah::R1, 16);
|
|
||||||
// Non-volatile saves
|
|
||||||
std::vector<powah::GPR> gp_regs{ABI_CALLEE_SAVED};
|
|
||||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
|
||||||
code.STD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
|
||||||
code.STDU(powah::R1, powah::R1, uint32_t(-stack_size));
|
|
||||||
code.STD(powah::R2, powah::R1, 40);
|
|
||||||
|
|
||||||
for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) {
|
|
||||||
IR::Inst* inst = &*iter;
|
|
||||||
switch (inst->GetOpcode()) {
|
|
||||||
#define OPCODE(name, type, ...) \
|
|
||||||
case IR::Opcode::name: \
|
|
||||||
EmitIR<IR::Opcode::name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#define A32OPC(name, type, ...) \
|
|
||||||
case IR::Opcode::A32##name: \
|
|
||||||
EmitIR<IR::Opcode::A32##name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#define A64OPC(name, type, ...) \
|
|
||||||
case IR::Opcode::A64##name: \
|
|
||||||
EmitIR<IR::Opcode::A64##name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#include "dynarmic/ir/opcodes.inc"
|
|
||||||
#undef OPCODE
|
|
||||||
#undef A32OPC
|
|
||||||
#undef A64OPC
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto const cycles_to_add = block.CycleCount();
|
|
||||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
|
||||||
code.LABEL(ctx.l_return);
|
|
||||||
code.ADDI(powah::R1, powah::R1, stack_size);
|
|
||||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
|
||||||
code.LD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
|
||||||
code.LD(powah::R0, powah::R1, 16);
|
|
||||||
code.MTLR(powah::R0);
|
|
||||||
code.LI(powah::R3, 0);
|
|
||||||
} else {
|
|
||||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
|
||||||
code.LABEL(ctx.l_return);
|
|
||||||
code.LI(powah::R3, 67); //non-zero ret
|
|
||||||
}
|
|
||||||
code.BLR();
|
|
||||||
code.ApplyRelocs();
|
|
||||||
|
|
||||||
/*
|
|
||||||
llvm-objcopy -I binary -O elf64-powerpc --rename-section=.data=.text,code test.bin test.elf && llvm-objdump -d test.elf
|
|
||||||
*/
|
|
||||||
static FILE* fp = fopen("test.bin", "wb");
|
|
||||||
fwrite(code.base, code.offset - start_offset, sizeof(uint32_t), fp);
|
|
||||||
fflush(fp);
|
|
||||||
|
|
||||||
ebi.size = code.offset - start_offset;
|
|
||||||
return ebi;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace biscuit {
|
|
||||||
class Assembler;
|
|
||||||
} // namespace biscuit
|
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
|
||||||
class Block;
|
|
||||||
class Inst;
|
|
||||||
enum class Cond;
|
|
||||||
enum class Opcode;
|
|
||||||
} // namespace Dynarmic::IR
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct EmittedBlockInfo {
|
|
||||||
std::uint32_t* entry_point;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EmitConfig {
|
|
||||||
bool enable_cycle_counting;
|
|
||||||
bool always_little_endian;
|
|
||||||
bool a64_variant;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EmitContext;
|
|
||||||
|
|
||||||
EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConfig& emit_conf);
|
|
||||||
template<IR::Opcode op>
|
|
||||||
void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/a32_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCheckBit>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetRegister>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A32Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ADDI(result, PPC64::RJIT, A32::RegNumber(inst->GetArg(0).GetA32RegRef()) * sizeof(u32));
|
|
||||||
code.LWZ(result, result, offsetof(A32JitState, regs));
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetVector>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetRegister>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A32Reg) {
|
|
||||||
auto const addr = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ADDI(addr, PPC64::RJIT, A32::RegNumber(inst->GetArg(0).GetA32RegRef()) * sizeof(u32));
|
|
||||||
code.STW(value, addr, offsetof(A32JitState, regs));
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetVector>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetCpsr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCVRaw>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCVQ>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZ>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZC>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetCFlag>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LD(result, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(result, result, 31, 31, 31);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32OrQFlag>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetGEFlagsCompressed>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32BXWritePC>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CallSupervisor>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExceptionRaised>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetFpscr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetFpscr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ClearExclusive>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coprocesor
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocInternalOperation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocSendOneWord>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocSendTwoWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocGetOneWord>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocGetTwoWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocLoadWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocStoreWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A64/a64_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetCheckBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.STW(value, PPC64::RJIT, offsetof(A64JitState, check_bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCFlag>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetNZCVRaw>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetNZCVRaw>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.STW(value, PPC64::RJIT, offsetof(A64JitState, pstate));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetW>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// Need to account for endianess here...
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.LWZ(result, PPC64::RJIT, offs);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetX>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.LD(result, PPC64::RJIT, offs);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetS>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetD>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetSP>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetFPCR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetFPSR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetW>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.RLDICL(tmp, value, 0, 32);
|
|
||||||
code.STD(tmp, PPC64::RJIT, offs);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetX>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.STD(value, PPC64::RJIT, offs);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetS>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetD>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetSP>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetFPCR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetFPSR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetPC>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64CallSupervisor>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExceptionRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataSynchronizationBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataMemoryBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCNTFRQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCNTPCT>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCTR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetDCZID>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetTPIDR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetTPIDRRO>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetTPIDR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ClearExclusive>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,933 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
// uint64_t pack2x1(uint32_t lo, uint32_t hi) { return (uint64_t)lo | ((uint64_t)hi << 32); }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Pack2x32To1x64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const lo = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const hi = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.SLDI(result, hi, 32);
|
|
||||||
code.OR(result, result, lo);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Pack2x64To1x128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t lsw(uint64_t a) { return (uint32_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLDICL(result, source, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t f(uint64_t a) { return (uint16_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantHalf>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t f(uint64_t a) { return (uint8_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantByte>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t msw(uint64_t a) { return a >> 32; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MostSignificantWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRDI(result, source, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return ((uint32_t)a) >> 31; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MostSignificantBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 1, 31, 31);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return (uint32_t)a == 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::IsZero32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZW(result, source);
|
|
||||||
code.SRWI(result, result, 5);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return a == 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::IsZero64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZD(result, source);
|
|
||||||
code.SRDI(result, result, 6);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return (a & 1) != 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::TestBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (inst->GetArg(1).IsImmediate()) {
|
|
||||||
auto const shift = inst->GetArg(1).GetImmediateAsU64();
|
|
||||||
if (shift > 0) {
|
|
||||||
code.RLDICL(result, source, (64 - shift - 1) & 0x3f, 63);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct jit {
|
|
||||||
uint64_t t;
|
|
||||||
uint64_t a;
|
|
||||||
};
|
|
||||||
uint64_t f(jit *p, uint64_t a, uint64_t b) {
|
|
||||||
bool n = (p->a & 0b1000) != 0;
|
|
||||||
bool z = (p->a & 0b0100) != 0;
|
|
||||||
bool c = (p->a & 0b0010) != 0;
|
|
||||||
bool v = (p->a & 0b0001) != 0;
|
|
||||||
return (p->a & 0b0001) == 0 ? a : b;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
static powah::GPR EmitConditionalSelectX(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const nzcv = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const then_ = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const else_ = ctx.reg_alloc.UseGpr(inst->GetArg(2));
|
|
||||||
switch (inst->GetArg(0).GetCond()) {
|
|
||||||
case IR::Cond::EQ: // Z == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 4);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::NE: // Z == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 4);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::CS: // C == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 2);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::CC: // C == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 2);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::MI: // N == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 8);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::PL: // N == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 8);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::VS: // V == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::VC: // V == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, else_, then_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::HI: // Z == 0 && C == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(nzcv, nzcv, 0, 29, 30);
|
|
||||||
code.CMPLDI(nzcv, 2);
|
|
||||||
code.ISELEQ(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::LS: // Z == 1 || C == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(nzcv, nzcv, 0, 29, 30);
|
|
||||||
code.CMPLDI(nzcv, 2);
|
|
||||||
code.ISELEQ(nzcv, else_, then_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::GE: { // N == V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, else_, then_);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::LT: { // N != V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::GT: { // Z == 0 && N == V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
powah::Label const l_ne = code.DefineLabel();
|
|
||||||
powah::Label const l_cc = code.DefineLabel();
|
|
||||||
powah::Label const l_fi = code.DefineLabel();
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(tmp, nzcv, 4);
|
|
||||||
code.BNE(powah::CR0, l_ne);
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.CMPLDI(nzcv, 0);
|
|
||||||
code.BGT(powah::CR0, l_fi);
|
|
||||||
code.LABEL(l_ne);
|
|
||||||
code.MR(then_, else_);
|
|
||||||
code.LABEL(l_cc);
|
|
||||||
code.MR(nzcv, then_);
|
|
||||||
code.LABEL(l_fi);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::LE: { // Z == 1 || N != V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp2 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
powah::Label const l_ne = code.DefineLabel();
|
|
||||||
code.MR(tmp2, then_);
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(tmp, nzcv, 4);
|
|
||||||
code.BNE(powah::CR0, l_ne);
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(tmp2, then_, else_);
|
|
||||||
code.LABEL(l_ne);
|
|
||||||
code.MR(nzcv, tmp2);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
return nzcv;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelect32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelect64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelectNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeft32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SLW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeft64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SLD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a, uint64_t s) { return a >> s; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRAW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRAD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_rotateright32
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::BitRotateRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLW(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::BitRotateRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightExtended>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeftMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SLW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeftMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SLD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRAW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRAD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Add32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.ADDC_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct jit {
|
|
||||||
uint32_t nzcv;
|
|
||||||
};
|
|
||||||
uint64_t addc(jit *p, uint64_t a, uint64_t b) {
|
|
||||||
long long unsigned int e;
|
|
||||||
uint64_t r = __builtin_addcll(a, b, p->nzcv & 0b0010, &e);
|
|
||||||
p->nzcv = (p->nzcv & 0b1101) | e;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Add64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.ADDC_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Sub32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SUBFC_(result, src_b, src_a);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Sub64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SUBFC_(result, src_b, src_a);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Mul32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLWO_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Mul64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedMultiplyHigh64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedMultiplyHigh64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedDiv32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVWU_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedDiv64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVDU_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedDiv32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVW_(result, src_a, src_b);
|
|
||||||
code.EXTSW(result, result);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedDiv64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVD_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::And32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp8 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = PPC64::RNZCV;
|
|
||||||
code.RLDICL(tmp3, src_a, 0, 32); // Truncate
|
|
||||||
code.AND(tmp3, tmp3, src_b);
|
|
||||||
code.CNTLZD(tmp9, tmp3);
|
|
||||||
code.RLWINM(tmp8, tmp3, 0, 0, 0);
|
|
||||||
code.SRDI(tmp9, tmp9, 6);
|
|
||||||
code.SLDI(tmp9, tmp9, 30);
|
|
||||||
code.OR(tmp9, tmp9, tmp8);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::And64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = PPC64::RNZCV;
|
|
||||||
code.AND(tmp3, src_a, src_b);
|
|
||||||
code.CNTLZD(tmp10, tmp3);
|
|
||||||
code.SRADI(tmp9, tmp3, 32);
|
|
||||||
code.SRDI(tmp10, tmp10, 6);
|
|
||||||
code.RLWINM(tmp9, tmp9, 0, 0, 0);
|
|
||||||
code.SLDI(tmp10, tmp10, 30);
|
|
||||||
code.OR(tmp9, tmp9, tmp10);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AndNot32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.NAND_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AndNot64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.NAND_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Eor32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.XOR_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Eor64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.XOR_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Or32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.OR_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Or64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.OR_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(lizzie): NZVC support for NOT
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Not32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NOT(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Not64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NOT(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendByteToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSB(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendHalfToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSH(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendByteToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSH(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendHalfToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSB(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendWordToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSW(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendByteToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendHalfToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendByteToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendHalfToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendWordToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLDICL(result, source, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendLongToQuad>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_bswap32
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRW(result, source);
|
|
||||||
//code.RLDICL(result, result, 0, 32);
|
|
||||||
} else {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ROTLWI(result, source, 24);
|
|
||||||
code.RLWIMI(result, source, 8, 8, 15);
|
|
||||||
code.RLWIMI(result, source, 8, 24, 31);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_bswap64
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseHalf>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRH(result, source);
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
} else {
|
|
||||||
code.ROTLWI(result, source, 24);
|
|
||||||
code.RLWIMI(result, source, 8, 0, 23);
|
|
||||||
code.CLRLDI(result, result, 48);
|
|
||||||
}
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseDual>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRD(result, source);
|
|
||||||
} else {
|
|
||||||
auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.MR(tmp3, source);
|
|
||||||
code.ROTLWI(tmp10, tmp3, 24);
|
|
||||||
code.SRDI(tmp9, tmp3, 32);
|
|
||||||
code.RLWIMI(tmp10, tmp3, 8, 8, 15);
|
|
||||||
code.RLWIMI(tmp10, tmp3, 8, 24, 31);
|
|
||||||
code.ROTLWI(tmp3, tmp9, 24);
|
|
||||||
code.RLWIMI(tmp3, tmp9, 8, 8, 15);
|
|
||||||
code.RLWIMI(tmp3, tmp9, 8, 24, 31);
|
|
||||||
code.RLDIMI(tmp3, tmp10, 32, 0);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_clz
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CountLeadingZeros32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZW(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_clz
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CountLeadingZeros64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZD(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ExtractRegister32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ExtractRegister64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ReplicateBit32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ReplicateBit64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxSigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxSigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxUnsigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLW(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxUnsigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLD(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinSigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPW(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinSigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinUnsigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLW(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinUnsigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLD(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPCompare32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPCompare64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDiv32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDiv64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMax32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMax64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMaxNumeric32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMaxNumeric64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMin32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMin64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMinNumeric32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMinNumeric64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMul32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMul64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulX32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulX64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSqrt32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSqrt64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToHalf>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToHalf>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,380 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAddWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSubWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packed
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAbsDiffSumU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSelect>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crypto
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESDecryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESEncryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESInverseMixColumns>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESMixColumns>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SM4AccessSubstitutionBox>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256Hash>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256MessageSchedule0>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256MessageSchedule1>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "dynarmic/interface/exclusive_monitor.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
ExclusiveMonitor::ExclusiveMonitor(std::size_t processor_count)
|
|
||||||
: exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {}
|
|
||||||
|
|
||||||
size_t ExclusiveMonitor::GetProcessorCount() const {
|
|
||||||
return exclusive_addresses.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Lock() {
|
|
||||||
lock.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Unlock() {
|
|
||||||
lock.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExclusiveMonitor::CheckAndClear(std::size_t processor_id, VAddr address) {
|
|
||||||
const VAddr masked_address = address & RESERVATION_GRANULE_MASK;
|
|
||||||
Lock();
|
|
||||||
if (exclusive_addresses[processor_id] != masked_address) {
|
|
||||||
Unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (VAddr& other_address : exclusive_addresses)
|
|
||||||
if (other_address == masked_address)
|
|
||||||
other_address = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Clear() {
|
|
||||||
Lock();
|
|
||||||
std::fill(exclusive_addresses.begin(), exclusive_addresses.end(), INVALID_EXCLUSIVE_ADDRESS);
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::ClearProcessor(size_t processor_id) {
|
|
||||||
Lock();
|
|
||||||
exclusive_addresses[processor_id] = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
enum class HostLoc : uint8_t {
|
|
||||||
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9,
|
|
||||||
R10, R11, R12, R13, R14, R15, R16, R17, R18, R19,
|
|
||||||
R20, R21, R22, R23, R24, R25, R26, R27, R28, R29,
|
|
||||||
R30, R31,
|
|
||||||
FR0, FR1, FR2, FR3, FR4, FR5, FR6, FR7, FR8, FR9,
|
|
||||||
FR10, FR11, FR12, FR13, FR14, FR15, FR16, FR17, FR18, FR19,
|
|
||||||
FR20, FR21, FR22, FR23, FR24, FR25, FR26, FR27, FR28, FR29,
|
|
||||||
FR30, FR31,
|
|
||||||
VR0, VR1, VR2, VR3, VR4, VR5, VR6, VR7, VR8, VR9,
|
|
||||||
VR10, VR11, VR12, VR13, VR14, VR15, VR16, VR17, VR18, VR19,
|
|
||||||
VR20, VR21, VR22, VR23, VR24, VR25, VR26, VR27, VR28, VR29,
|
|
||||||
VR30, VR31,
|
|
||||||
FirstSpill,
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::PPC64
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <ranges>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/common/always_false.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
constexpr size_t spill_offset = offsetof(StackLayout, spill);
|
|
||||||
constexpr size_t spill_slot_size = sizeof(decltype(StackLayout::spill)::value_type);
|
|
||||||
|
|
||||||
static bool IsValuelessType(IR::Type type) {
|
|
||||||
return type == IR::Type::Table;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostLocInfo::UpdateUses() {
|
|
||||||
accumulated_uses += uses_this_inst;
|
|
||||||
uses_this_inst = 0;
|
|
||||||
if (accumulated_uses == expected_uses) {
|
|
||||||
values.clear();
|
|
||||||
accumulated_uses = 0;
|
|
||||||
expected_uses = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RegAlloc::IsValueLive(IR::Inst* inst) const {
|
|
||||||
return !!ValueLocation(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::UpdateAllUses() {
|
|
||||||
for (auto& gpr : gprs)
|
|
||||||
gpr.UpdateUses();
|
|
||||||
for (auto& fpr : fprs)
|
|
||||||
fpr.UpdateUses();
|
|
||||||
for (auto& spill : spills)
|
|
||||||
spill.UpdateUses();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineAsExisting(IR::Inst* inst, IR::Value arg) {
|
|
||||||
ASSERT(!ValueLocation(inst));
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
inst->ReplaceUsesWith(arg);
|
|
||||||
} else {
|
|
||||||
auto& info = ValueInfo(arg.GetInst());
|
|
||||||
info.values.emplace_back(inst);
|
|
||||||
info.expected_uses += inst->UseCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::AssertNoMoreUses() const {
|
|
||||||
const auto is_empty = [](const auto& i) { return i.IsCompletelyEmpty(); };
|
|
||||||
ASSERT(std::all_of(gprs.begin(), gprs.end(), is_empty));
|
|
||||||
ASSERT(std::all_of(fprs.begin(), fprs.end(), is_empty));
|
|
||||||
ASSERT(std::all_of(spills.begin(), spills.end(), is_empty));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<u32> RegAlloc::AllocateRegister(const std::array<HostLocInfo, 32>& regs) const {
|
|
||||||
auto const order = PPC64::GPR_ORDER;
|
|
||||||
if (auto const it = std::find_if(order.begin(), order.end(), [&](u32 i) {
|
|
||||||
return regs[i].values.empty() && !regs[i].locked;
|
|
||||||
}); it != order.end())
|
|
||||||
return *it;
|
|
||||||
// TODO: Actual proper LRU
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::SpillGpr(u32 index) {
|
|
||||||
ASSERT(!gprs[index].locked && !gprs[index].realized);
|
|
||||||
if (!gprs[index].values.empty()) {
|
|
||||||
const u32 new_location_index = FindFreeSpill();
|
|
||||||
code.STD(powah::GPR{index}, powah::R1, spill_offset + new_location_index * spill_slot_size);
|
|
||||||
spills[new_location_index] = std::exchange(gprs[index], {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::SpillFpr(u32 index) {
|
|
||||||
ASSERT(!fprs[index].locked && !fprs[index].realized);
|
|
||||||
if (!fprs[index].values.empty()) {
|
|
||||||
const u32 new_location_index = FindFreeSpill();
|
|
||||||
//code.FSD(powah::FPR{index}, spill_offset + new_location_index * spill_slot_size, powah::sp);
|
|
||||||
spills[new_location_index] = std::exchange(fprs[index], {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 RegAlloc::FindFreeSpill() const {
|
|
||||||
const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); });
|
|
||||||
ASSERT(iter != spills.end() && "All spill locations are full");
|
|
||||||
return u32(iter - spills.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<HostLoc> RegAlloc::ValueLocation(const IR::Inst* value) const {
|
|
||||||
const auto fn = [value](const HostLocInfo& info) {
|
|
||||||
return info.Contains(value);
|
|
||||||
};
|
|
||||||
if (const auto iter = std::ranges::find_if(gprs, fn); iter != gprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::R0) + u32(iter - gprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(fprs, fn); iter != fprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::FR0) + u32(iter - fprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(vprs, fn); iter != vprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::VR0) + u32(iter - vprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(spills, fn); iter != spills.end())
|
|
||||||
return HostLoc(u32(HostLoc::FirstSpill) + u32(iter - spills.begin()));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool HostLocIsGpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::R0) && u8(h) <= u8(HostLoc::R31);
|
|
||||||
}
|
|
||||||
inline bool HostLocIsFpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::FR0) && u8(h) <= u8(HostLoc::FR31);
|
|
||||||
}
|
|
||||||
inline bool HostLocIsVpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::VR0) && u8(h) <= u8(HostLoc::VR31);
|
|
||||||
}
|
|
||||||
inline std::variant<powah::GPR, powah::FPR> HostLocToReg(HostLoc h) noexcept {
|
|
||||||
if (HostLocIsGpr(h))
|
|
||||||
return powah::GPR{uint32_t(h)};
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
HostLocInfo& RegAlloc::ValueInfo(HostLoc h) {
|
|
||||||
if (u8(h) >= u8(HostLoc::R0) && u8(h) <= u8(HostLoc::R31))
|
|
||||||
return gprs[size_t(h)];
|
|
||||||
else if (u8(h) >= u8(HostLoc::FR0) && u8(h) <= u8(HostLoc::FR31))
|
|
||||||
return gprs[size_t(h) - size_t(HostLoc::FR0)];
|
|
||||||
else if (u8(h) >= u8(HostLoc::VR0) && u8(h) <= u8(HostLoc::VR31))
|
|
||||||
return vprs[size_t(h) - size_t(HostLoc::VR0)];
|
|
||||||
auto const index = size_t(h) - size_t(HostLoc::FirstSpill);
|
|
||||||
ASSERT(index <= spills.size());
|
|
||||||
return spills[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) {
|
|
||||||
const auto fn = [value](const HostLocInfo& info) {
|
|
||||||
return info.Contains(value);
|
|
||||||
};
|
|
||||||
if (const auto iter = std::find_if(gprs.begin(), gprs.end(), fn); iter != gprs.end())
|
|
||||||
return *iter;
|
|
||||||
else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), fn); iter != fprs.end())
|
|
||||||
return *iter;
|
|
||||||
else if (const auto iter = std::find_if(spills.begin(), spills.end(), fn); iter != spills.end())
|
|
||||||
return *iter;
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Defines a register RegLock to use (and locks it)
|
|
||||||
RegLock<powah::GPR> RegAlloc::ScratchGpr() {
|
|
||||||
auto const r = AllocateRegister(gprs);
|
|
||||||
return RegLock(*this, powah::GPR{*r});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Uses the given GPR of the argument
|
|
||||||
RegLock<powah::GPR> RegAlloc::UseGpr(IR::Value arg) {
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
// HOLY SHIT EVIL HAXX
|
|
||||||
auto const reg = ScratchGpr();
|
|
||||||
auto const imm = arg.GetImmediateAsU64();
|
|
||||||
if (imm >= 0xffffffff) {
|
|
||||||
auto const lo = uint32_t(imm >> 0), hi = uint32_t(imm >> 32);
|
|
||||||
if (lo == hi) {
|
|
||||||
code.LIS(reg, imm >> 16);
|
|
||||||
code.ORI(reg, reg, imm & 0xffff);
|
|
||||||
code.RLDIMI(reg, reg, 32, 0);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "larger >32bit imms");
|
|
||||||
}
|
|
||||||
} else if (imm > 0xffff && imm <= 0xffffffff) {
|
|
||||||
code.LIS(reg, imm >> 16);
|
|
||||||
code.ORI(reg, reg, imm & 0xffff);
|
|
||||||
} else if (imm <= 0xffff) {
|
|
||||||
code.LI(reg, imm);
|
|
||||||
}
|
|
||||||
return reg;
|
|
||||||
} else {
|
|
||||||
auto const loc = ValueLocation(arg.GetInst());
|
|
||||||
ASSERT(loc && HostLocIsGpr(*loc));
|
|
||||||
return RegLock(*this, std::get<powah::GPR>(HostLocToReg(*loc)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept {
|
|
||||||
ASSERT(!ValueLocation(inst) && "inst has already been defined");
|
|
||||||
ValueInfo(HostLoc(gpr.index)).values.push_back(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineValue(IR::Inst* inst, IR::Value arg) noexcept {
|
|
||||||
ASSERT(!ValueLocation(inst) && "inst has already been defined");
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
HostLoc const loc{u8(ScratchGpr().value.index)};
|
|
||||||
ValueInfo(loc).values.push_back(inst);
|
|
||||||
auto const value = arg.GetImmediateAsU64();
|
|
||||||
if (value >= 0x7fff) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
} else {
|
|
||||||
//code.LI(HostLocToReg(loc), value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT(ValueLocation(arg.GetInst()) && "arg must already be defined");
|
|
||||||
const HostLoc loc = *ValueLocation(arg.GetInst());
|
|
||||||
ValueInfo(loc).values.push_back(inst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <optional>
|
|
||||||
#include <random>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/stack_layout.h"
|
|
||||||
#include "dynarmic/backend/ppc64/hostloc.h"
|
|
||||||
#include "dynarmic/ir/cond.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/value.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct HostLocInfo final {
|
|
||||||
std::vector<const IR::Inst*> values;
|
|
||||||
size_t uses_this_inst = 0;
|
|
||||||
size_t accumulated_uses = 0;
|
|
||||||
size_t expected_uses = 0;
|
|
||||||
/// @brief Lock usage of this register UNTIL a DefineValue() is issued
|
|
||||||
bool locked = false;
|
|
||||||
bool realized = false;
|
|
||||||
bool Contains(const IR::Inst* value) const {
|
|
||||||
return std::find(values.begin(), values.end(), value) != values.end();
|
|
||||||
}
|
|
||||||
void SetupScratchLocation() {
|
|
||||||
ASSERT(IsCompletelyEmpty());
|
|
||||||
realized = true;
|
|
||||||
}
|
|
||||||
bool IsCompletelyEmpty() const {
|
|
||||||
return values.empty() && !locked && !realized && !accumulated_uses && !expected_uses && !uses_this_inst;
|
|
||||||
}
|
|
||||||
void UpdateUses();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegAlloc;
|
|
||||||
|
|
||||||
/// @brief Allows to use RAII to denote liveness/locking of a given register
|
|
||||||
/// this basically means that we can use temporals and not need to go thru
|
|
||||||
/// any weird deallocation stuffs :)
|
|
||||||
template<typename T> struct RegLock {
|
|
||||||
constexpr RegLock(RegAlloc& reg_alloc, T const value) noexcept
|
|
||||||
: reg_alloc{reg_alloc}
|
|
||||||
, value{value}
|
|
||||||
{
|
|
||||||
SetLock(true);
|
|
||||||
}
|
|
||||||
inline ~RegLock() noexcept { SetLock(false); }
|
|
||||||
constexpr operator T const&() noexcept { return value; }
|
|
||||||
constexpr operator T() const noexcept { return value; }
|
|
||||||
inline void SetLock(bool v) noexcept;
|
|
||||||
RegAlloc& reg_alloc;
|
|
||||||
const T value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegAlloc {
|
|
||||||
explicit RegAlloc(powah::Context& code) : code{code} {}
|
|
||||||
bool IsValueLive(IR::Inst* inst) const;
|
|
||||||
void DefineAsExisting(IR::Inst* inst, IR::Value arg);
|
|
||||||
|
|
||||||
void SpillAll();
|
|
||||||
void UpdateAllUses();
|
|
||||||
void AssertNoMoreUses() const;
|
|
||||||
|
|
||||||
RegLock<powah::GPR> ScratchGpr();
|
|
||||||
RegLock<powah::GPR> UseGpr(IR::Value arg);
|
|
||||||
void DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept;
|
|
||||||
void DefineValue(IR::Inst* inst, IR::Value arg) noexcept;
|
|
||||||
private:
|
|
||||||
template<typename T>
|
|
||||||
friend struct RegLock;
|
|
||||||
|
|
||||||
std::optional<u32> AllocateRegister(const std::array<HostLocInfo, 32>& regs) const;
|
|
||||||
void SpillGpr(u32 index);
|
|
||||||
void SpillFpr(u32 index);
|
|
||||||
u32 FindFreeSpill() const;
|
|
||||||
|
|
||||||
std::optional<HostLoc> ValueLocation(const IR::Inst* value) const;
|
|
||||||
HostLocInfo& ValueInfo(HostLoc host_loc);
|
|
||||||
HostLocInfo& ValueInfo(const IR::Inst* value);
|
|
||||||
|
|
||||||
powah::Context& code;
|
|
||||||
std::array<HostLocInfo, 32> gprs;
|
|
||||||
std::array<HostLocInfo, 32> fprs;
|
|
||||||
std::array<HostLocInfo, 32> vprs;
|
|
||||||
std::array<HostLocInfo, SpillCount> spills;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> inline void RegLock<powah::GPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.gprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
template<> inline void RegLock<powah::FPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.fprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
template<> inline void RegLock<powah::VPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.vprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
constexpr size_t SpillCount = 16;
|
|
||||||
|
|
||||||
struct alignas(16) StackLayout {
|
|
||||||
std::array<u64, SpillCount> spill;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(StackLayout) % 16 == 0);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/hostloc.h"
|
|
||||||
#include "dynarmic/common/spin_lock.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
/*
|
|
||||||
void acquire(atomic_flag* lock) {
|
|
||||||
while(atomic_flag_test_and_set_explicit( lock, memory_order_acquire))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void EmitSpinLockLock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void release(atomic_flag* lock) {
|
|
||||||
atomic_flag_clear_explicit(lock, memory_order_release);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void EmitSpinLockUnlock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct SpinLockImpl {
|
|
||||||
void Initialize();
|
|
||||||
powah::Context code;
|
|
||||||
void* page = nullptr;
|
|
||||||
void (*lock)(volatile int*);
|
|
||||||
void (*unlock)(volatile int*);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::once_flag flag;
|
|
||||||
SpinLockImpl impl;
|
|
||||||
|
|
||||||
void SpinLockImpl::Initialize() {
|
|
||||||
page = mmap(nullptr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
||||||
ASSERT(page != nullptr);
|
|
||||||
code = powah::Context(page, 4096);
|
|
||||||
lock = reinterpret_cast<void (*)(volatile int*)>(code.base);
|
|
||||||
EmitSpinLockLock(code, Backend::PPC64::ABI_PARAM1, Backend::PPC64::ABI_PARAM2);
|
|
||||||
code.BLR();
|
|
||||||
unlock = reinterpret_cast<void (*)(volatile int*)>(code.base);
|
|
||||||
EmitSpinLockUnlock(code, Backend::PPC64::ABI_PARAM1, Backend::PPC64::ABI_PARAM2);
|
|
||||||
code.BLR();
|
|
||||||
// TODO: free the page, rework the stupid spinlock API
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void SpinLock::Lock() noexcept {
|
|
||||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
|
||||||
impl.lock(&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpinLock::Unlock() noexcept {
|
|
||||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
|
||||||
impl.unlock(&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
void EmitSpinLockLock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp);
|
|
||||||
void EmitSpinLockUnlock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp);
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -1664,7 +1664,7 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
|||||||
.size = overlap.SizeBytes(),
|
.size = overlap.SizeBytes(),
|
||||||
});
|
});
|
||||||
new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size);
|
new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size);
|
||||||
runtime.CopyBuffer(new_buffer, overlap, FixSmallVectorADL(copies), true);
|
runtime.CopyBuffer(new_buffer, overlap, copies, true);
|
||||||
#ifdef YUZU_LEGACY
|
#ifdef YUZU_LEGACY
|
||||||
if (immediately_free)
|
if (immediately_free)
|
||||||
runtime.Finish();
|
runtime.Finish();
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ void MemoryManager::FlushCaching() {
|
|||||||
if (accumulator.InvalidateAll([this](GPUVAddr addr, size_t size) {
|
if (accumulator.InvalidateAll([this](GPUVAddr addr, size_t size) {
|
||||||
GetSubmappedRangeImpl<false>(addr, size, page_stash2);
|
GetSubmappedRangeImpl<false>(addr, size, page_stash2);
|
||||||
})) {
|
})) {
|
||||||
rasterizer->InnerInvalidation(VideoCommon::FixSmallVectorADL(page_stash2));
|
rasterizer->InnerInvalidation(page_stash2);
|
||||||
page_stash2.clear();
|
page_stash2.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
|
|||||||
if (src_buffer == staging_pool.StreamBuf() && can_reorder_upload) {
|
if (src_buffer == staging_pool.StreamBuf() && can_reorder_upload) {
|
||||||
scheduler.RecordWithUploadBuffer([src_buffer, dst_buffer, vk_copies](
|
scheduler.RecordWithUploadBuffer([src_buffer, dst_buffer, vk_copies](
|
||||||
vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
||||||
upload_cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
upload_cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -482,7 +482,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
|
|||||||
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER,
|
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||||
}
|
}
|
||||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies);
|
||||||
if (barrier) {
|
if (barrier) {
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, WRITE_BARRIER);
|
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, WRITE_BARRIER);
|
||||||
|
|||||||
@@ -1642,7 +1642,7 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
|
|||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
0, nullptr, nullptr, pre_barriers);
|
0, nullptr, nullptr, pre_barriers);
|
||||||
cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VideoCommon::FixSmallVectorADL(vk_copies));
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies);
|
||||||
cmdbuf.PipelineBarrier(
|
cmdbuf.PipelineBarrier(
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||||
@@ -2006,7 +2006,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
|||||||
|
|
||||||
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask,
|
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask,
|
||||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||||
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, VideoCommon::FixSmallVectorADL(vk_copies));
|
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, vk_copies);
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples);
|
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples);
|
||||||
@@ -2060,7 +2060,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
|||||||
|
|
||||||
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, was_initialized,
|
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, was_initialized,
|
||||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||||
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, was_initialized, VideoCommon::FixSmallVectorADL(vk_copies));
|
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, was_initialized, vk_copies);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (is_rescaled) {
|
if (is_rescaled) {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ void TextureCache<P>::RunGarbageCollector() {
|
|||||||
}
|
}
|
||||||
if (must_download) {
|
if (must_download) {
|
||||||
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
image.DownloadMemory(map, copies);
|
image.DownloadMemory(map, copies);
|
||||||
runtime.Finish();
|
runtime.Finish();
|
||||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span, swizzle_data_buffer);
|
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span, swizzle_data_buffer);
|
||||||
@@ -629,7 +629,7 @@ void TextureCache<P>::DownloadMemory(DAddr cpu_addr, size_t size) {
|
|||||||
for (const ImageId image_id : images) {
|
for (const ImageId image_id : images) {
|
||||||
Image& image = slot_images[image_id];
|
Image& image = slot_images[image_id];
|
||||||
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
image.DownloadMemory(map, copies);
|
image.DownloadMemory(map, copies);
|
||||||
runtime.Finish();
|
runtime.Finish();
|
||||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span,
|
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span,
|
||||||
@@ -893,7 +893,7 @@ void TextureCache<P>::CommitAsyncFlushes() {
|
|||||||
for (const PendingDownload& download_info : download_ids) {
|
for (const PendingDownload& download_info : download_ids) {
|
||||||
if (download_info.is_swizzle) {
|
if (download_info.is_swizzle) {
|
||||||
Image& image = slot_images[download_info.object_id];
|
Image& image = slot_images[download_info.object_id];
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
image.DownloadMemory(download_map, copies);
|
image.DownloadMemory(download_map, copies);
|
||||||
download_map.offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
|
download_map.offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||||
}
|
}
|
||||||
@@ -926,7 +926,7 @@ void TextureCache<P>::PopAsyncFlushes() {
|
|||||||
auto& download_buffer = download_map[download_info.async_buffer_id];
|
auto& download_buffer = download_map[download_info.async_buffer_id];
|
||||||
if (download_info.is_swizzle) {
|
if (download_info.is_swizzle) {
|
||||||
const ImageBase& image = slot_images[download_info.object_id];
|
const ImageBase& image = slot_images[download_info.object_id];
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
download_buffer.offset -= Common::AlignUp(image.unswizzled_size_bytes, 64);
|
download_buffer.offset -= Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||||
std::span<u8> download_span =
|
std::span<u8> download_span =
|
||||||
download_buffer.mapped_span.subspan(download_buffer.offset);
|
download_buffer.mapped_span.subspan(download_buffer.offset);
|
||||||
@@ -964,7 +964,7 @@ void TextureCache<P>::PopAsyncFlushes() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Image& image = slot_images[download_info.object_id];
|
Image& image = slot_images[download_info.object_id];
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
image.DownloadMemory(download_map, copies);
|
image.DownloadMemory(download_map, copies);
|
||||||
download_map.offset += image.unswizzled_size_bytes;
|
download_map.offset += image.unswizzled_size_bytes;
|
||||||
}
|
}
|
||||||
@@ -977,7 +977,7 @@ void TextureCache<P>::PopAsyncFlushes() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const ImageBase& image = slot_images[download_info.object_id];
|
const ImageBase& image = slot_images[download_info.object_id];
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FullDownloadCopies(image.info);
|
||||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, download_span, swizzle_data_buffer);
|
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, download_span, swizzle_data_buffer);
|
||||||
download_map.offset += image.unswizzled_size_bytes;
|
download_map.offset += image.unswizzled_size_bytes;
|
||||||
download_span = download_span.subspan(image.unswizzled_size_bytes);
|
download_span = download_span.subspan(image.unswizzled_size_bytes);
|
||||||
@@ -1160,7 +1160,7 @@ void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging)
|
|||||||
gpu_memory->ReadBlock(gpu_addr, mapped_span.data(), mapped_span.size_bytes(),
|
gpu_memory->ReadBlock(gpu_addr, mapped_span.data(), mapped_span.size_bytes(),
|
||||||
VideoCommon::CacheType::NoTextureCache);
|
VideoCommon::CacheType::NoTextureCache);
|
||||||
const auto uploads = FullUploadSwizzles(image.info);
|
const auto uploads = FullUploadSwizzles(image.info);
|
||||||
runtime.AccelerateImageUpload(image, staging, FixSmallVectorADL(uploads), 0, 0);
|
runtime.AccelerateImageUpload(image, staging, uploads, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,11 +1168,11 @@ void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging)
|
|||||||
*gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
|
*gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
|
||||||
if (True(image.flags & ImageFlagBits::Converted)) {
|
if (True(image.flags & ImageFlagBits::Converted)) {
|
||||||
unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
|
unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
|
||||||
auto copies = FixSmallVectorADL(UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, unswizzle_data_buffer));
|
auto copies = UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, unswizzle_data_buffer);
|
||||||
ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies);
|
ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies);
|
||||||
image.UploadMemory(staging, copies);
|
image.UploadMemory(staging, copies);
|
||||||
} else {
|
} else {
|
||||||
const auto copies = FixSmallVectorADL(UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, mapped_span));
|
const auto copies = UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, mapped_span);
|
||||||
image.UploadMemory(staging, copies);
|
image.UploadMemory(staging, copies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1401,7 +1401,7 @@ void TextureCache<P>::TickAsyncDecode() {
|
|||||||
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image));
|
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image));
|
||||||
std::memcpy(staging.mapped_span.data(), async_decode->decoded_data.data(),
|
std::memcpy(staging.mapped_span.data(), async_decode->decoded_data.data(),
|
||||||
async_decode->decoded_data.size());
|
async_decode->decoded_data.size());
|
||||||
image.UploadMemory(staging, FixSmallVectorADL(async_decode->copies));
|
image.UploadMemory(staging, async_decode->copies);
|
||||||
image.flags &= ~ImageFlagBits::IsDecoding;
|
image.flags &= ~ImageFlagBits::IsDecoding;
|
||||||
has_uploads = true;
|
has_uploads = true;
|
||||||
i = async_decodes.erase(i);
|
i = async_decodes.erase(i);
|
||||||
@@ -1469,7 +1469,7 @@ void TextureCache<P>::TickAsyncUnswizzle() {
|
|||||||
|
|
||||||
if (z_count > 0) {
|
if (z_count > 0) {
|
||||||
const auto uploads = FullUploadSwizzles(task.info);
|
const auto uploads = FullUploadSwizzles(task.info);
|
||||||
runtime.AccelerateImageUpload(image, task.staging_buffer, FixSmallVectorADL(uploads), z_start, z_count);
|
runtime.AccelerateImageUpload(image, task.staging_buffer, uploads, z_start, z_count);
|
||||||
task.last_submitted_offset += (static_cast<size_t>(z_count) * task.bytes_per_slice);
|
task.last_submitted_offset += (static_cast<size_t>(z_count) * task.bytes_per_slice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1730,9 +1730,9 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
|
|||||||
const u32 down_shift = can_rescale ? resolution.down_shift : 0;
|
const u32 down_shift = can_rescale ? resolution.down_shift : 0;
|
||||||
auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift);
|
auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift);
|
||||||
if (overlap.info.num_samples != new_image.info.num_samples) {
|
if (overlap.info.num_samples != new_image.info.num_samples) {
|
||||||
runtime.CopyImageMSAA(new_image, overlap, FixSmallVectorADL(copies));
|
runtime.CopyImageMSAA(new_image, overlap, copies);
|
||||||
} else {
|
} else {
|
||||||
runtime.CopyImage(new_image, overlap, FixSmallVectorADL(copies));
|
runtime.CopyImage(new_image, overlap, copies);
|
||||||
}
|
}
|
||||||
new_image.modification_tick = overlap.modification_tick;
|
new_image.modification_tick = overlap.modification_tick;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -122,25 +122,4 @@ void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase*
|
|||||||
|
|
||||||
[[nodiscard]] u32 MapSizeBytes(const ImageBase& image);
|
[[nodiscard]] u32 MapSizeBytes(const ImageBase& image);
|
||||||
|
|
||||||
// TODO: Remove once Debian STABLE no longer has such outdated boost
|
|
||||||
// This is a gcc bug where ADL lookup fails for range niebloids of std::span<T>
|
|
||||||
// for any given type of the static_vector/small_vector, etc which makes a whole mess
|
|
||||||
// for anything using std::span<T> so we just do this terrible hack on older versions of
|
|
||||||
// GCC12 because people actually still use stable debian so... yeah
|
|
||||||
// One may say: "This is bad for performance" - to which I say, using GCC 12 you already know
|
|
||||||
// what kind of bs you will be dealing with anyways.
|
|
||||||
template<typename T, size_t N>
|
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
|
||||||
[[nodiscard]] boost::container::small_vector<T, N> FixSmallVectorADL(const boost::container::small_vector<T, N>& v) {
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
[[nodiscard]] std::vector<T> FixSmallVectorADL(const boost::container::small_vector<T, N>& v) {
|
|
||||||
std::vector<T> u;
|
|
||||||
for (auto const& e : v)
|
|
||||||
u.push_back(e);
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ Tools for Eden and other subprojects. When adding new scripts please use `#!/bin
|
|||||||
- `shellcheck.sh`: Ensure POSIX compliance (and syntax sanity) for all tools in this directory and subdirectories.
|
- `shellcheck.sh`: Ensure POSIX compliance (and syntax sanity) for all tools in this directory and subdirectories.
|
||||||
- `llvmpipe-run.sh`: Sets environment variables needed to run any command (or Eden) with llvmpipe.
|
- `llvmpipe-run.sh`: Sets environment variables needed to run any command (or Eden) with llvmpipe.
|
||||||
- `optimize-assets.sh`: Optimizes PNG assets with OptiPng.
|
- `optimize-assets.sh`: Optimizes PNG assets with OptiPng.
|
||||||
- `setup-cross-sysroot.sh`: Allows to quickly create a sysroot of a given system for cross compilation (experimental).
|
|
||||||
- `update-cpm.sh`: Updates CPM.cmake to the latest version.
|
- `update-cpm.sh`: Updates CPM.cmake to the latest version.
|
||||||
- `update-icons.sh`: Rebuild all icons (macOS, Windows, bitmaps) based on the master SVG file (`dist/dev.eden_emu.eden.svg`)
|
- `update-icons.sh`: Rebuild all icons (macOS, Windows, bitmaps) based on the master SVG file (`dist/dev.eden_emu.eden.svg`)
|
||||||
* Also optimizes the master SVG
|
* Also optimizes the master SVG
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
die() {
|
|
||||||
echo "$@" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
help() {
|
|
||||||
cat << EOF
|
|
||||||
--arch <name> Specify the target architecture (default: ppc64)
|
|
||||||
--os <name> Specify the OS sysroot to use (default: freebsd)
|
|
||||||
--sysroot <path> Specify sysroot to use
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
TARGET_ARCH="ppc64"
|
|
||||||
TARGET_OS="freebsd"
|
|
||||||
TARGET_CMAKE="$TARGET_ARCH-pc-$TARGET_OS"
|
|
||||||
BASE_DIR="$PWD"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
case "$1" in
|
|
||||||
--arch) shift; TARGET_ARCH=$1; [ -z "$TARGET_ARCH" ] && die "Expected argument";;
|
|
||||||
--os) shift; TARGET_OS=$1; [ -z "$TARGET_OS" ] && die "Expected argument";;
|
|
||||||
--sysroot) shift; SYSROOT=$1; [ -z "$SYSROOT" ] && die "Expected argument";;
|
|
||||||
--help) help "$@";;
|
|
||||||
--*) die "Invalid option $1" ;;
|
|
||||||
"$0" | "") break;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
[ -z "$SYSROOT" ] && SYSROOT="$HOME/opt/$TARGET_ARCH-$TARGET_OS/sysroot"
|
|
||||||
mkdir -p "$SYSROOT" && cd "$SYSROOT"
|
|
||||||
case "$TARGET_OS" in
|
|
||||||
freebsd*)
|
|
||||||
case "$TARGET_ARCH" in
|
|
||||||
ppc64pe) URL="https://download.freebsd.org/ftp/releases/powerpc/powerpc64pe/14.3-RELEASE/base.txz" break;;
|
|
||||||
ppc64le) URL="https://download.freebsd.org/ftp/releases/powerpc/powerpc64le/14.3-RELEASE/base.txz" break;;
|
|
||||||
ppc64) URL="https://download.freebsd.org/ftp/releases/powerpc/powerpc64/14.3-RELEASE/base.txz" break;;
|
|
||||||
ppc) URL="https://download.freebsd.org/ftp/releases/powerpc/powerpc/14.3-RELEASE/base.txz" break;;
|
|
||||||
amd64 | x86_64) URL="https://download.freebsd.org/ftp/releases/amd64/14.3-RELEASE/base.txz" break;;
|
|
||||||
arm64*) URL="https://download.freebsd.org/ftp/releases/arm64/$TARGET_ARCH/14.3-RELEASE/base.txz" break;;
|
|
||||||
arm*) URL="https://download.freebsd.org/ftp/releases/arm/$TARGET_ARCH/14.3-RELEASE/base.txz" break;;
|
|
||||||
*) die "Unknown arch $TARGET_ARCH" break;;
|
|
||||||
esac
|
|
||||||
[ -z "$TARGET_CMAKE" ] && TARGET_CMAKE="$TARGET_ARCH-pc-$TARGET_OS"
|
|
||||||
[ -f "base.txz" ] || fetch "$URL" || die "Can't download"
|
|
||||||
tar -xvzf base.txz
|
|
||||||
break;;
|
|
||||||
*) die "Unknown OS $TARGET_OS" break;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
[ -z "$CC" ] && CC=$(which clang)
|
|
||||||
[ -z "$CXX" ] && CXX=$(which clang++)
|
|
||||||
|
|
||||||
TOOLCHAIN_FILE="$BASE_DIR/$TARGET_CMAKE-toolchain.cmake"
|
|
||||||
cat << EOF >"$TOOLCHAIN_FILE"
|
|
||||||
# Script to generate .cmake toolchain files :)
|
|
||||||
# See https://man.freebsd.org/cgi/man.cgi?query=cmake-toolchains&sektion=7&manpath=FreeBSD+13.2-RELEASE+and+Ports
|
|
||||||
|
|
||||||
set(CMAKE_SYSROOT "$SYSROOT")
|
|
||||||
set(CMAKE_STAGING_PREFIX "$SYSROOT")
|
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER $CC)
|
|
||||||
set(CMAKE_CXX_COMPILER $CXX)
|
|
||||||
set(CMAKE_C_FLAGS "--target=$TARGET_CMAKE")
|
|
||||||
set(CMAKE_CXX_FLAGS "--target=$TARGET_CMAKE")
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# cmake \
|
|
||||||
# -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
|
|
||||||
# -DCMAKE_BUILD_TYPE=Release \
|
|
||||||
# -B "build-$TARGET_CMAKE" \
|
|
||||||
# -DDYNARMIC_TESTS=ON \
|
|
||||||
# -DENABLE_QT=OFF \
|
|
||||||
# -DENABLE_SDL2=OFF \
|
|
||||||
# -DYUZU_USE_CPM=ON \
|
|
||||||
# -DYUZU_USE_EXTERNAL_FFMPEG=ON
|
|
||||||
#cmake --build "build-$TARGET_CMAKE" dynarmic_tests -- -j8
|
|
||||||
Reference in New Issue
Block a user