Compare commits

...

19 commits

Author SHA1 Message Date
CamilleLaVey
4c0916915f fix license headers+ 2026-04-05 03:43:32 +02:00
CamilleLaVey
d646a57f75 [texture_cache] Adjusted GC logic for the iterations with older or obsolete textures 2026-04-05 03:43:32 +02:00
CamilleLaVey
e343ee9524 [texture_cache] Reduce garbage collection logic by simplifying conditions and thresholds 2026-04-05 03:43:32 +02:00
CamilleLaVey
18ad42f996 small fix for the softlock after lru cache removal 2026-04-05 03:43:32 +02:00
CamilleLaVey
cc553379d8 Gido MEOW 2026-04-05 03:43:32 +02:00
CamilleLaVey
df113ea18b [texture_cache] Replace LRU index with frame tick in ImageBase + update garbage collection logic 2026-04-05 03:43:32 +02:00
CamilleLaVey
1d844296f4 I got meowed by Gidoly 2026-04-05 03:43:32 +02:00
CamilleLaVey
fb53c236b2 [buffer_cache] Removal of LRU inside buffer cache and replaced with tick operations inside frames. 2026-04-05 03:43:32 +02:00
CamilleLaVey
6fa854001d [maxwell] Removed prefetching for ProcessCommands 2026-04-05 03:43:32 +02:00
CamilleLaVey
ee124f3284 [maxwell] Refactor execution mask initialization to use fill() instead of reset() 2026-04-05 03:43:32 +02:00
lizzie
ac99ea96da
[dynarmic] fix bayonetta 3 regression due to LUT in #3718 (#3822)
Some checks failed
tx-src / sources (push) Has been cancelled
Check Strings / check-strings (push) Has been cancelled
minor oversight

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3822
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-03 17:33:44 +02:00
lizzie
d1b7824443
[meta] Restore base icon (#3809)
Some checks failed
tx-src / sources (push) Has been cancelled
Check Strings / check-strings (push) Has been cancelled
Merge AFTER april fools
Signed-off-by: lizzie lizzie@eden-emu.dev

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3809
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-02 06:06:46 +02:00
wildcard
34fa39eae8
[texture_cache] Skip alias synchronization in texture cache when the image has no aliases. (#3740)
PrepareImage() is on a very hot path and previously called SynchronizeAliases() unconditionally.  For most images, aliased_images` is empty, so this created unnecessary overhead, now we only synchronize only when image requires it

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3740
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-04-02 06:06:16 +02:00
lizzie
9ace6742d7
[docs] update multiplayer section with metaserver info (#3722)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3722
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-01 21:59:37 +02:00
crueter
79f29abcba
[core] Fix renderdoc API garbage (#3816)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3816
2026-04-01 21:02:20 +02:00
crueter
3ce5463d2d
[cmake] Remove shader dir regeneration (#3813)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
We ***do not*** support BSD make. Period.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3813
2026-04-01 08:10:39 +02:00
lizzie
cae70c30fa
[dynarmic] fix GCC 12.2 complaints for regalloc.h (#3812)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3812
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-01 07:26:46 +02:00
lizzie
bcceced96d
[dynarmic] fix GetDecoderTable() making the compiler nervous due to the big table that gets made into the stack (#3799)
issue on stbale gcc debian

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3799
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-01 07:05:42 +02:00
lizzie
82e374f66c
[meta] April Fools 2026 icon (#3802)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
art

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3802
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-04-01 03:07:50 +02:00
34 changed files with 3123 additions and 1901 deletions

89
dist/icon_variations/aprilfools2026.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1 @@
#43fcfcff

View file

@ -334,7 +334,7 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
```
[Caveats](./Caveats.md#haikuos).

View file

@ -56,7 +56,7 @@ Use this when you need to connect to a multiplayer room for LDN functionality in
- Multiplayer Options Configured in Eden Settings
- Network Access
## Steps
### Steps
There are 2 primary methods that you can use to connect to an existing room, depending on how the room is hosted.
- Joining a Public Lobby
@ -70,7 +70,7 @@ There are 2 primary methods that you can use to connect to an existing room, dep
</aside>
### Joining a Public Lobby
## Joining a Public Lobby
1. Open Eden and navigate to *Multiplayer → Browse Public Game Lobby*.
2. The **Public Room Browser** will now open and display a list of publicly accessible rooms. Find one you want to connect to and double click it.
@ -90,7 +90,7 @@ If the hoster has not made the lobby public, or you don't want to find it in the
---
# Hosting a Multiplayer Room
## Hosting a Multiplayer Room
Use this guide for when you want to host a multiplayer lobby to play with others in Eden. In order to have someone access the room from outside your local network, see the *Access Your Multiplayer Room Externally* section for next steps.
**Click [Here](https://evilperson1337.notion.site/Hosting-a-Multiplayer-Room-2c357c2edaf6819481dbe8a99926cea2) for a version of this guide with images & visual elements.**
@ -100,7 +100,7 @@ Use this guide for when you want to host a multiplayer lobby to play with others
- Network Access
- Ability to allow programs through the firewall on your device.
## Steps
### Steps
1. Open Eden and navigate to *Emulation → Multiplayer → Create Room.*
2. Fill out the following information in the popup dialog box.
@ -120,7 +120,7 @@ Use this guide for when you want to host a multiplayer lobby to play with others
---
# Access Your Multiplayer Room Externally
## Access Your Multiplayer Room Externally
Quite often the person with whom you want to play is located off of your internal network (LAN). If you want to host a room and play with them you will need to get your devices to communicate with each other. This guide will go over your options on how to do this so that you can play together.
**Click [Here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for a version of this guide with images & visual elements.**
@ -129,9 +129,9 @@ Quite often the person with whom you want to play is located off of your interna
- Eden set up and Functioning
- Network Access
## Options
### Options
### Port Forwarding
#### Port Forwarding
- **Difficulty Level**: High
@ -148,8 +148,9 @@ The process works by creating a static mapping—often called a “port-forward
For our purposes we would pick the port we want to expose (*e.g. 24872*) and we would access our router's configuration and create a port-forward rule to send the traffic from an external connection to your local machine over our specified port (*24872)*. The exact way to do so, varies greatly by router manufacturer - and sometimes require contacting your ISP to do so depending on your agreement. You can look up your router on [*portforward.com*](https://portforward.com/router.htm) which may have instructions on how to do so for your specific equipment. If it is not there, you will have to use Google/ChatGPT to determine the steps for your equipment.
Remember you can't have one port open for multiple devices at the same time - you must only host from one device (or do more convoluted networking which we will not cover here).
### Use a Tunnelling Service
#### Use a Tunnelling Service
- **Difficulty Level**: Easy
<aside>
@ -167,7 +168,7 @@ For our purposes we would spawn the listener for the port that way chose when ho
- [*Playit.GG*](https://playit.gg/)
### Use a VPN Service
#### Use a VPN Service
- **Difficulty**: Easy
@ -189,7 +190,7 @@ The VPN solution is a good compromise between the tunnelling solution and port f
---
# Finding the Server Information for a Multiplayer Room
## Finding the Server Information for a Multiplayer Room
Use this guide when you need to determine the connection information for the Public Multiplayer Lobby you are connected to.
**Click [Here](https://evilperson1337.notion.site/Finding-the-Server-Information-for-a-Multiplayer-Room-2c557c2edaf6809e94e8ed3429b9eb26) for a version of this guide with images & visual elements.**
@ -198,7 +199,7 @@ Use this guide when you need to determine the connection information for the Pub
- Eden set up and configured
- Internet Access
## Steps
### Steps
### Method 1: Grabbing the Address from the Log File
1. Open Eden and Connect to the room you want to identify.
@ -222,7 +223,7 @@ Use this guide when you need to determine the connection information for the Pub
2. Open the terminal supported by your operating system.
3. Run one of the following commands, replacing *<Name>* with the name of the server from step 1.
### PowerShell Command [Windows Users]
#### PowerShell Command [Windows Users]
```powershell
# Calls the API to get the address and port information
@ -235,7 +236,7 @@ Use this guide when you need to determine the connection information for the Pub
#}
```
### CURL Command [MacOS/Linux Users] **Requires jq*
#### CURL Command [MacOS/Linux Users] **Requires jq*
```bash
# Calls the API to get the address and port information
@ -252,7 +253,7 @@ Use this guide when you need to determine the connection information for the Pub
---
# Multiplayer for Local Co-Op Games
## Multiplayer for Local Co-Op Games
Use this guide when you want to play with a friend on a different system for games that only support local co-op.
**Click [Here](https://evilperson1337.notion.site/Multiplayer-for-Local-Co-Op-Games-2c657c2edaf680c59975ec6b52022a2d) for a version of this guide with images & visual elements.**
@ -271,7 +272,7 @@ In either situation at its core, we are emulating an input device on the host ma
- Parsec is free to use for personal, non-commercial use. For instructions on how to set up an account and install the client you should refer to the Parsec documentation on it's site.
- Parsec client installed on your machine and remote (friend's) machine
## Steps
### Steps
<aside>
@ -294,3 +295,22 @@ This guide will assume you are the one hosting the game and go over things *Pars
10. Set up the remote player's controller.
11. Hit **OK** to apply the changes.
12. Launch the game you want to play and enter the co-op mode. How this works depends on the game, so you will have to look in the menus or online to find out.
## Metaserver troubleshooting
If you can't connect to the metaserver, it's likely your ISP is blocking the requests.
### Linux and Steamdeck
Most Linux systems and Steamdeck should allow to modify the base `/etc/hosts` file, this should fix the DNS lookup issue; hence add the following to said file:
```
28.165.181.135 api.ynet-fun.xyz api.ynet-fun.xyz
```
### Zapret
In `lists/list-general.txt` add the following:
```
api.ynet-fun.xyz
ynet-fun.xyz
```

View file

@ -1,139 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <deque>
#include <memory>
#include <type_traits>
#include "common/common_types.h"
namespace Common {
template <class Traits>
class LeastRecentlyUsedCache {
using ObjectType = typename Traits::ObjectType;
using TickType = typename Traits::TickType;
struct Item {
ObjectType obj;
TickType tick;
Item* next{};
Item* prev{};
};
public:
LeastRecentlyUsedCache() : first_item{}, last_item{} {}
~LeastRecentlyUsedCache() = default;
size_t Insert(ObjectType obj, TickType tick) {
const auto new_id = Build();
auto& item = item_pool[new_id];
item.obj = obj;
item.tick = tick;
Attach(item);
return new_id;
}
void Touch(size_t id, TickType tick) {
auto& item = item_pool[id];
if (item.tick >= tick) {
return;
}
item.tick = tick;
if (&item == last_item) {
return;
}
Detach(item);
Attach(item);
}
void Free(size_t id) {
auto& item = item_pool[id];
Detach(item);
item.prev = nullptr;
item.next = nullptr;
free_items.push_back(id);
}
template <typename Func>
void ForEachItemBelow(TickType tick, Func&& func) {
static constexpr bool RETURNS_BOOL =
std::is_same_v<std::invoke_result<Func, ObjectType>, bool>;
Item* iterator = first_item;
while (iterator) {
if (static_cast<s64>(tick) - static_cast<s64>(iterator->tick) < 0) {
return;
}
Item* next = iterator->next;
if constexpr (RETURNS_BOOL) {
if (func(iterator->obj)) {
return;
}
} else {
func(iterator->obj);
}
iterator = next;
}
}
private:
size_t Build() {
if (free_items.empty()) {
const size_t item_id = item_pool.size();
auto& item = item_pool.emplace_back();
item.next = nullptr;
item.prev = nullptr;
return item_id;
}
const size_t item_id = free_items.front();
free_items.pop_front();
auto& item = item_pool[item_id];
item.next = nullptr;
item.prev = nullptr;
return item_id;
}
void Attach(Item& item) {
if (!first_item) {
first_item = &item;
}
if (!last_item) {
last_item = &item;
} else {
item.prev = last_item;
last_item->next = &item;
item.next = nullptr;
last_item = &item;
}
}
void Detach(Item& item) {
if (item.prev) {
item.prev->next = item.next;
}
if (item.next) {
item.next->prev = item.prev;
}
if (&item == first_item) {
first_item = item.next;
if (first_item) {
first_item->prev = nullptr;
}
}
if (&item == last_item) {
last_item = item.prev;
if (last_item) {
last_item->next = nullptr;
}
}
}
std::deque<Item> item_pool;
std::deque<size_t> free_items;
Item* first_item{};
Item* last_item{};
};
} // namespace Common

View file

@ -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-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@ -51,10 +51,12 @@ void RenderdocAPI::ToggleCapture() {
if (!rdoc_api) [[unlikely]] {
return;
}
auto* api = static_cast<RENDERDOC_API_1_6_0*>(rdoc_api);
if (!is_capturing) {
rdoc_api->StartFrameCapture(NULL, NULL);
api->StartFrameCapture(NULL, NULL);
} else {
rdoc_api->EndFrameCapture(NULL, NULL);
api->EndFrameCapture(NULL, NULL);
}
is_capturing = !is_capturing;
}

View file

@ -6,8 +6,6 @@
#pragma once
struct RENDERDOC_API_1_7_0;
namespace Tools {
class RenderdocAPI {
@ -18,7 +16,7 @@ public:
void ToggleCapture();
private:
RENDERDOC_API_1_7_0* rdoc_api{};
void* rdoc_api{};
bool is_capturing{false};
};

View file

@ -316,8 +316,8 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
return current_location->index;
}
ASSERT(!ValueInfo(*current_location).realized);
ASSERT(ValueInfo(*current_location).locked);
ASSERT(!bool(ValueInfo(*current_location).realized));
ASSERT(bool(ValueInfo(*current_location).locked));
if constexpr (required_kind == HostLoc::Kind::Gpr) {
const int new_location_index = AllocateRegister(gprs, gpr_order);

View file

@ -1985,6 +1985,13 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
// output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
// }
template<size_t fsize, bool unsigned_, FP::RoundingMode rounding_mode, size_t fbits>
static void EmitFPVectorToFixedThunk(VectorArray<mcl::unsigned_integer_of_size<fsize>>& output, const VectorArray<mcl::unsigned_integer_of_size<fsize>>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
using FPT = mcl::unsigned_integer_of_size<fsize>;
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
}
template<size_t fsize, bool unsigned_>
void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const size_t fbits = inst->GetArg(1).GetU8();
@ -2106,43 +2113,88 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(code, inst, src);
return;
}
auto const fpt_fn = [fbits, rounding]() -> void (*)(VectorArray<mcl::unsigned_integer_of_size<fsize>>& output, const VectorArray<mcl::unsigned_integer_of_size<fsize>>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
#define ROUNDING_MODE_CASE(CASE, N) \
if (rounding == FP::RoundingMode::CASE && fsize >= (N) && fbits == (N)) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, N>;
#define ROUNDING_MODE_SWITCH(CASE) \
ROUNDING_MODE_CASE(CASE, 0x00) \
ROUNDING_MODE_CASE(CASE, 0x01) \
ROUNDING_MODE_CASE(CASE, 0x02) \
ROUNDING_MODE_CASE(CASE, 0x03) \
ROUNDING_MODE_CASE(CASE, 0x04) \
ROUNDING_MODE_CASE(CASE, 0x05) \
ROUNDING_MODE_CASE(CASE, 0x06) \
ROUNDING_MODE_CASE(CASE, 0x07) \
ROUNDING_MODE_CASE(CASE, 0x08) \
ROUNDING_MODE_CASE(CASE, 0x09) \
ROUNDING_MODE_CASE(CASE, 0x0a) \
ROUNDING_MODE_CASE(CASE, 0x0b) \
ROUNDING_MODE_CASE(CASE, 0x0c) \
ROUNDING_MODE_CASE(CASE, 0x0d) \
ROUNDING_MODE_CASE(CASE, 0x0e) \
ROUNDING_MODE_CASE(CASE, 0x0f) \
ROUNDING_MODE_CASE(CASE, 0x10) \
ROUNDING_MODE_CASE(CASE, 0x11) \
ROUNDING_MODE_CASE(CASE, 0x12) \
ROUNDING_MODE_CASE(CASE, 0x13) \
ROUNDING_MODE_CASE(CASE, 0x14) \
ROUNDING_MODE_CASE(CASE, 0x15) \
ROUNDING_MODE_CASE(CASE, 0x16) \
ROUNDING_MODE_CASE(CASE, 0x17) \
ROUNDING_MODE_CASE(CASE, 0x18) \
ROUNDING_MODE_CASE(CASE, 0x19) \
ROUNDING_MODE_CASE(CASE, 0x1a) \
ROUNDING_MODE_CASE(CASE, 0x1b) \
ROUNDING_MODE_CASE(CASE, 0x1c) \
ROUNDING_MODE_CASE(CASE, 0x1d) \
ROUNDING_MODE_CASE(CASE, 0x1e) \
ROUNDING_MODE_CASE(CASE, 0x1f) \
ROUNDING_MODE_CASE(CASE, 0x20) \
ROUNDING_MODE_CASE(CASE, 0x21) \
ROUNDING_MODE_CASE(CASE, 0x22) \
ROUNDING_MODE_CASE(CASE, 0x23) \
ROUNDING_MODE_CASE(CASE, 0x24) \
ROUNDING_MODE_CASE(CASE, 0x25) \
ROUNDING_MODE_CASE(CASE, 0x26) \
ROUNDING_MODE_CASE(CASE, 0x27) \
ROUNDING_MODE_CASE(CASE, 0x28) \
ROUNDING_MODE_CASE(CASE, 0x29) \
ROUNDING_MODE_CASE(CASE, 0x2a) \
ROUNDING_MODE_CASE(CASE, 0x2b) \
ROUNDING_MODE_CASE(CASE, 0x2c) \
ROUNDING_MODE_CASE(CASE, 0x2d) \
ROUNDING_MODE_CASE(CASE, 0x2e) \
ROUNDING_MODE_CASE(CASE, 0x2f) \
ROUNDING_MODE_CASE(CASE, 0x30) \
ROUNDING_MODE_CASE(CASE, 0x31) \
ROUNDING_MODE_CASE(CASE, 0x32) \
ROUNDING_MODE_CASE(CASE, 0x33) \
ROUNDING_MODE_CASE(CASE, 0x34) \
ROUNDING_MODE_CASE(CASE, 0x35) \
ROUNDING_MODE_CASE(CASE, 0x36) \
ROUNDING_MODE_CASE(CASE, 0x37) \
ROUNDING_MODE_CASE(CASE, 0x38) \
ROUNDING_MODE_CASE(CASE, 0x39) \
ROUNDING_MODE_CASE(CASE, 0x3a) \
ROUNDING_MODE_CASE(CASE, 0x3b) \
ROUNDING_MODE_CASE(CASE, 0x3c) \
ROUNDING_MODE_CASE(CASE, 0x3d) \
ROUNDING_MODE_CASE(CASE, 0x3e) \
ROUNDING_MODE_CASE(CASE, 0x3f)
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
auto const func = [rounding]() -> void(*)(VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
switch (rounding) {
case FP::RoundingMode::ToNearest_TieEven:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieEven, fpsr));
};
case FP::RoundingMode::TowardsPlusInfinity:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsPlusInfinity, fpsr));
};
case FP::RoundingMode::TowardsMinusInfinity:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsMinusInfinity, fpsr));
};
case FP::RoundingMode::TowardsZero:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsZero, fpsr));
};
case FP::RoundingMode::ToNearest_TieAwayFromZero:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieAwayFromZero, fpsr));
};
case FP::RoundingMode::ToOdd:
return [](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToOdd, fpsr));
};
}
// FUCK YOU MSVC, FUCKING DEPTH CANT EVEN HANDLE 8+16+32+64 DEPTH OF A ELSE STATMENT YOU FUCKING STUPID
// BURN MSVC BURN IT STUPID COMPILER CAN'T EVEN COMPILE THE MOST BASIC C++
ROUNDING_MODE_SWITCH(ToNearest_TieEven)
ROUNDING_MODE_SWITCH(TowardsPlusInfinity)
ROUNDING_MODE_SWITCH(TowardsMinusInfinity)
ROUNDING_MODE_SWITCH(TowardsZero)
ROUNDING_MODE_SWITCH(ToNearest_TieAwayFromZero)
#undef ROUNDING_MODE_SWITCH
#undef ROUNDING_MODE_CASE
return nullptr;
}();
EmitTwoOpFallback<3>(code, ctx, inst, func);
EmitTwoOpFallback<3>(code, ctx, inst, fpt_fn);
}
void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) {

View file

@ -50,7 +50,7 @@ public:
}
inline void ReadLock() noexcept {
ASSERT(size_t(is_being_used_count) + 1 < (std::numeric_limits<decltype(is_being_used_count)>::max)());
ASSERT(!is_scratch);
ASSERT(!bool(is_scratch));
is_being_used_count++;
}
inline void WriteLock() noexcept {

View file

@ -36,25 +36,19 @@ inline size_t ToFastLookupIndexArm(u32 instruction) noexcept {
} // namespace detail
template<typename V>
constexpr ArmDecodeTable<V> GetArmDecodeTable() noexcept {
std::vector<ArmMatcher<V>> list = {
static ArmDecodeTable<V> GetArmDecodeTable() noexcept {
ArmDecodeTable<V> table{};
for (size_t i = 0; i < table.size(); ++i) {
// PLEASE HEAP ELLIDE
for (auto const& e : std::vector<ArmMatcher<V>>{
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./arm.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) {
return mcl::bit::count_ones(matcher1.GetMask()) > mcl::bit::count_ones(matcher2.GetMask());
});
ArmDecodeTable<V> table{};
for (size_t i = 0; i < table.size(); ++i) {
for (auto matcher : list) {
const auto expect = detail::ToFastLookupIndexArm(matcher.GetExpected());
const auto mask = detail::ToFastLookupIndexArm(matcher.GetMask());
}) {
auto const expect = detail::ToFastLookupIndexArm(e.GetExpected());
auto const mask = detail::ToFastLookupIndexArm(e.GetMask());
if ((i & mask) == expect) {
table[i].push_back(matcher);
table[i].push_back(e);
}
}
}
@ -62,7 +56,7 @@ constexpr ArmDecodeTable<V> GetArmDecodeTable() noexcept {
}
template<typename V>
std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruction) noexcept {
static std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruction) noexcept {
alignas(64) static const auto table = GetArmDecodeTable<V>();
const auto matches_instruction = [instruction](const auto& matcher) {
return matcher.Matches(instruction);
@ -73,7 +67,7 @@ std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruc
}
template<typename V>
std::optional<std::string_view> GetNameARM(u32 inst) noexcept {
static std::optional<std::string_view> GetNameARM(u32 inst) noexcept {
std::vector<std::pair<std::string_view, ArmMatcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./arm.inc"

View file

@ -1,316 +1,265 @@
// Barrier instructions
INST(arm_DMB, "DMB", "1111010101111111111100000101oooo") // v7
INST(arm_DSB, "DSB", "1111010101111111111100000100oooo") // v7
INST(arm_ISB, "ISB", "1111010101111111111100000110oooo") // v7
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// DO NOT REORDER
// Branch instructions
INST(arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv") // v5
INST(arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm") // v5
INST(arm_B, "B", "cccc1010vvvvvvvvvvvvvvvvvvvvvvvv") // v1
INST(arm_BL, "BL", "cccc1011vvvvvvvvvvvvvvvvvvvvvvvv") // v1
INST(arm_BX, "BX", "cccc000100101111111111110001mmmm") // v4T
INST(arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm") // v5J
// CRC32 instructions
INST(arm_CRC32, "CRC32", "cccc00010zz0nnnndddd00000100mmmm") // v8
INST(arm_CRC32C, "CRC32C", "cccc00010zz0nnnndddd00100100mmmm") // v8
// Coprocessor instructions
INST(arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM") // v2 (CDP2: v5)
INST(arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv") // v2 (LDC2: v5)
INST(arm_MCR, "MCR", "cccc1110ooo0NNNNttttppppooo1MMMM") // v2 (MCR2: v5)
INST(arm_MCRR, "MCRR", "cccc11000100uuuuttttppppooooMMMM") // v5E (MCRR2: v6)
INST(arm_MRC, "MRC", "cccc1110ooo1NNNNttttppppooo1MMMM") // v2 (MRC2: v5)
INST(arm_MRRC, "MRRC", "cccc11000101uuuuttttppppooooMMMM") // v5E (MRRC2: v6)
INST(arm_STC, "STC", "cccc110pudw0nnnnDDDDppppvvvvvvvv") // v2 (STC2: v5)
// Data Processing instructions
INST(arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_ADC_reg, "ADC (reg)", "cccc0000101Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_ADC_rsr, "ADC (rsr)", "cccc0000101Snnnnddddssss0rr1mmmm") // v1
INST(arm_ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_ADD_reg, "ADD (reg)", "cccc0000100Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_ADD_rsr, "ADD (rsr)", "cccc0000100Snnnnddddssss0rr1mmmm") // v1
INST(arm_AND_imm, "AND (imm)", "cccc0010000Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_AND_reg, "AND (reg)", "cccc0000000Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_AND_rsr, "AND (rsr)", "cccc0000000Snnnnddddssss0rr1mmmm") // v1
INST(arm_BIC_imm, "BIC (imm)", "cccc0011110Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_BIC_reg, "BIC (reg)", "cccc0001110Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_BIC_rsr, "BIC (rsr)", "cccc0001110Snnnnddddssss0rr1mmmm") // v1
INST(arm_CMN_imm, "CMN (imm)", "cccc00110111nnnn0000rrrrvvvvvvvv") // v1
INST(arm_CMN_reg, "CMN (reg)", "cccc00010111nnnn0000vvvvvrr0mmmm") // v1
INST(arm_CMN_rsr, "CMN (rsr)", "cccc00010111nnnn0000ssss0rr1mmmm") // v1
INST(arm_CMP_imm, "CMP (imm)", "cccc00110101nnnn0000rrrrvvvvvvvv") // v1
INST(arm_CMP_reg, "CMP (reg)", "cccc00010101nnnn0000vvvvvrr0mmmm") // v1
INST(arm_CMP_rsr, "CMP (rsr)", "cccc00010101nnnn0000ssss0rr1mmmm") // v1
INST(arm_EOR_imm, "EOR (imm)", "cccc0010001Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_EOR_reg, "EOR (reg)", "cccc0000001Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_EOR_rsr, "EOR (rsr)", "cccc0000001Snnnnddddssss0rr1mmmm") // v1
INST(arm_MOV_imm, "MOV (imm)", "cccc0011101S0000ddddrrrrvvvvvvvv") // v1
INST(arm_MOV_reg, "MOV (reg)", "cccc0001101S0000ddddvvvvvrr0mmmm") // v1
INST(arm_MOV_rsr, "MOV (rsr)", "cccc0001101S0000ddddssss0rr1mmmm") // v1
INST(arm_MVN_imm, "MVN (imm)", "cccc0011111S0000ddddrrrrvvvvvvvv") // v1
INST(arm_MVN_reg, "MVN (reg)", "cccc0001111S0000ddddvvvvvrr0mmmm") // v1
INST(arm_MVN_rsr, "MVN (rsr)", "cccc0001111S0000ddddssss0rr1mmmm") // v1
INST(arm_ORR_imm, "ORR (imm)", "cccc0011100Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_ORR_reg, "ORR (reg)", "cccc0001100Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_ORR_rsr, "ORR (rsr)", "cccc0001100Snnnnddddssss0rr1mmmm") // v1
INST(arm_RSB_imm, "RSB (imm)", "cccc0010011Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_RSB_reg, "RSB (reg)", "cccc0000011Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_RSB_rsr, "RSB (rsr)", "cccc0000011Snnnnddddssss0rr1mmmm") // v1
INST(arm_RSC_imm, "RSC (imm)", "cccc0010111Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_RSC_reg, "RSC (reg)", "cccc0000111Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_RSC_rsr, "RSC (rsr)", "cccc0000111Snnnnddddssss0rr1mmmm") // v1
INST(arm_SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm") // v1
INST(arm_SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv") // v1
INST(arm_SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm") // v1
INST(arm_SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm") // v1
INST(arm_TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv") // v1
INST(arm_TEQ_reg, "TEQ (reg)", "cccc00010011nnnn0000vvvvvrr0mmmm") // v1
INST(arm_TEQ_rsr, "TEQ (rsr)", "cccc00010011nnnn0000ssss0rr1mmmm") // v1
INST(arm_TST_imm, "TST (imm)", "cccc00110001nnnn0000rrrrvvvvvvvv") // v1
INST(arm_TST_reg, "TST (reg)", "cccc00010001nnnn0000vvvvvrr0mmmm") // v1
INST(arm_TST_rsr, "TST (rsr)", "cccc00010001nnnn0000ssss0rr1mmmm") // v1
// Exception Generating instructions
INST(arm_BKPT, "BKPT", "cccc00010010vvvvvvvvvvvv0111vvvv") // v5
INST(arm_SVC, "SVC", "cccc1111vvvvvvvvvvvvvvvvvvvvvvvv") // v1
INST(arm_UDF, "UDF", "111001111111------------1111----")
// Extension instructions
INST(arm_SXTB, "SXTB", "cccc011010101111ddddrr000111mmmm") // v6
INST(arm_SXTB16, "SXTB16", "cccc011010001111ddddrr000111mmmm") // v6
INST(arm_SXTH, "SXTH", "cccc011010111111ddddrr000111mmmm") // v6
INST(arm_SXTAB, "SXTAB", "cccc01101010nnnnddddrr000111mmmm") // v6
INST(arm_SXTAB16, "SXTAB16", "cccc01101000nnnnddddrr000111mmmm") // v6
INST(arm_SXTAH, "SXTAH", "cccc01101011nnnnddddrr000111mmmm") // v6
INST(arm_UXTB, "UXTB", "cccc011011101111ddddrr000111mmmm") // v6
INST(arm_UXTB16, "UXTB16", "cccc011011001111ddddrr000111mmmm") // v6
INST(arm_UXTH, "UXTH", "cccc011011111111ddddrr000111mmmm") // v6
INST(arm_UXTAB, "UXTAB", "cccc01101110nnnnddddrr000111mmmm") // v6
INST(arm_UXTAB16, "UXTAB16", "cccc01101100nnnnddddrr000111mmmm") // v6
INST(arm_UXTAH, "UXTAH", "cccc01101111nnnnddddrr000111mmmm") // v6
// Hint instructions
INST(arm_PLD_imm, "PLD (imm)", "11110101uz01nnnn1111iiiiiiiiiiii") // v5E for PLD; v7 for PLDW
INST(arm_PLD_reg, "PLD (reg)", "11110111uz01nnnn1111iiiiitt0mmmm") // v5E for PLD; v7 for PLDW
INST(arm_SEV, "SEV", "----0011001000001111000000000100") // v6K
INST(arm_SEVL, "SEVL", "----0011001000001111000000000101") // v8
INST(arm_WFE, "WFE", "----0011001000001111000000000010") // v6K
INST(arm_WFI, "WFI", "----0011001000001111000000000011") // v6K
INST(arm_YIELD, "YIELD", "----0011001000001111000000000001") // v6K
INST(arm_NOP, "Reserved Hint", "----0011001000001111------------")
INST(arm_NOP, "Reserved Hint", "----001100100000111100000000----")
// Synchronization Primitive instructions
INST(arm_CLREX, "CLREX", "11110101011111111111000000011111") // v6K
INST(arm_SWP, "SWP", "cccc00010000nnnntttt00001001uuuu") // v2S (v6: Deprecated)
INST(arm_SWPB, "SWPB", "cccc00010100nnnntttt00001001uuuu") // v2S (v6: Deprecated)
INST(arm_STL, "STL", "cccc00011000nnnn111111001001tttt") // v8
INST(arm_STLEX, "STLEX", "cccc00011000nnnndddd11101001tttt") // v8
INST(arm_STREX, "STREX", "cccc00011000nnnndddd11111001mmmm") // v6
INST(arm_LDA, "LDA", "cccc00011001nnnndddd110010011111") // v8
INST(arm_LDAEX, "LDAEX", "cccc00011001nnnndddd111010011111") // v8
INST(arm_LDREX, "LDREX", "cccc00011001nnnndddd111110011111") // v6
INST(arm_STLEXD, "STLEXD", "cccc00011010nnnndddd11101001mmmm") // v8
INST(arm_STREXD, "STREXD", "cccc00011010nnnndddd11111001mmmm") // v6K
INST(arm_LDAEXD, "LDAEXD", "cccc00011011nnnndddd111010011111") // v8
INST(arm_LDREXD, "LDREXD", "cccc00011011nnnndddd111110011111") // v6K
INST(arm_STLB, "STLB", "cccc00011100nnnn111111001001tttt") // v8
INST(arm_STLEXB, "STLEXB", "cccc00011100nnnndddd11101001mmmm") // v8
INST(arm_STREXB, "STREXB", "cccc00011100nnnndddd11111001mmmm") // v6K
INST(arm_LDAB, "LDAB", "cccc00011101nnnndddd110010011111") // v8
INST(arm_LDAEXB, "LDAEXB", "cccc00011101nnnndddd111010011111") // v8
INST(arm_LDREXB, "LDREXB", "cccc00011101nnnndddd111110011111") // v6K
INST(arm_STLH, "STLH", "cccc00011110nnnn111111001001mmmm") // v8
INST(arm_STLEXH, "STLEXH", "cccc00011110nnnndddd11101001mmmm") // v8
INST(arm_STREXH, "STREXH", "cccc00011110nnnndddd11111001mmmm") // v6K
INST(arm_LDAH, "LDAH", "cccc00011111nnnndddd110010011111") // v8
INST(arm_LDAEXH, "LDAEXH", "cccc00011111nnnndddd111010011111") // v8
INST(arm_LDREXH, "LDREXH", "cccc00011111nnnndddd111110011111") // v6K
// Load/Store instructions
INST(arm_LDRBT, "LDRBT (A1)", "----0100-111--------------------") // v1
INST(arm_LDRBT, "LDRBT (A2)", "----0110-111---------------0----") // v1
INST(arm_LDRHT, "LDRHT (A1)", "----0000-111------------1011----") // v6T2
INST(arm_LDRHT, "LDRHT (A1)", "----0000-1111111--------1011----") // v6T2
INST(arm_LDRHT, "LDRHT (A2)", "----0000-011--------00001011----") // v6T2
INST(arm_LDRSBT, "LDRSBT (A1)", "----0000-111------------1101----") // v6T2
INST(arm_LDRSBT, "LDRSBT (A2)", "----0000-011--------00001101----") // v6T2
INST(arm_LDRSHT, "LDRSHT (A1)", "----0000-111------------1111----") // v6T2
INST(arm_LDRSHT, "LDRSHT (A2)", "----0000-011--------00001111----") // v6T2
INST(arm_LDRT, "LDRT (A1)", "----0100-011--------------------") // v1
INST(arm_LDRT, "LDRT (A2)", "----0110-011---------------0----") // v1
INST(arm_STRBT, "STRBT (A1)", "----0100-110--------------------") // v1
INST(arm_STRBT, "STRBT (A2)", "----0110-110---------------0----") // v1
INST(arm_STRHT, "STRHT (A1)", "----0000-110------------1011----") // v6T2
INST(arm_STRHT, "STRHT (A2)", "----0000-010--------00001011----") // v6T2
INST(arm_STRT, "STRT (A1)", "----0100-010--------------------") // v1
INST(arm_STRT, "STRT (A2)", "----0110-010---------------0----") // v1
INST(arm_LDR_lit, "LDR (lit)", "cccc0101u0011111ttttvvvvvvvvvvvv") // v1
INST(arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnttttvvvvvvvvvvvv") // v1
INST(arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnttttvvvvvrr0mmmm") // v1
INST(arm_LDRB_lit, "LDRB (lit)", "cccc0101u1011111ttttvvvvvvvvvvvv") // v1
INST(arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnttttvvvvvvvvvvvv") // v1
INST(arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnttttvvvvvrr0mmmm") // v1
INST(arm_LDRD_lit, "LDRD (lit)", "cccc0001u1001111ttttvvvv1101vvvv") // v5E
INST(arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnttttvvvv1101vvvv") // v5E
INST(arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnntttt00001101mmmm") // v5E
INST(arm_LDRH_lit, "LDRH (lit)", "cccc000pu1w11111ttttvvvv1011vvvv") // v4
INST(arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnttttvvvv1011vvvv") // v4
INST(arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnntttt00001011mmmm") // v4
INST(arm_LDRSB_lit, "LDRSB (lit)", "cccc0001u1011111ttttvvvv1101vvvv") // v4
INST(arm_LDRSB_imm, "LDRSB (imm)", "cccc000pu1w1nnnnttttvvvv1101vvvv") // v4
INST(arm_LDRSB_reg, "LDRSB (reg)", "cccc000pu0w1nnnntttt00001101mmmm") // v4
INST(arm_LDRSH_lit, "LDRSH (lit)", "cccc0001u1011111ttttvvvv1111vvvv") // v4
INST(arm_LDRSH_imm, "LDRSH (imm)", "cccc000pu1w1nnnnttttvvvv1111vvvv") // v4
INST(arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnntttt00001111mmmm") // v4
INST(arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnttttvvvvvvvvvvvv") // v1
INST(arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnttttvvvvvrr0mmmm") // v1
INST(arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnttttvvvvvvvvvvvv") // v1
INST(arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnttttvvvvvrr0mmmm") // v1
INST(arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnttttvvvv1111vvvv") // v5E
INST(arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnntttt00001111mmmm") // v5E
INST(arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnttttvvvv1011vvvv") // v4
INST(arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnntttt00001011mmmm") // v4
// Load/Store Multiple instructions
INST(arm_LDM, "LDM", "cccc100010w1nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_LDMDA, "LDMDA", "cccc100000w1nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_LDMDB, "LDMDB", "cccc100100w1nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_LDMIB, "LDMIB", "cccc100110w1nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_LDM_usr, "LDM (usr reg)", "----100--101--------------------") // v1
INST(arm_LDM_eret, "LDM (exce ret)", "----100--1-1----1---------------") // v1
INST(arm_STM, "STM", "cccc100010w0nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_STMDA, "STMDA", "cccc100000w0nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_STMDB, "STMDB", "cccc100100w0nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_STMIB, "STMIB", "cccc100110w0nnnnxxxxxxxxxxxxxxxx") // v1
INST(arm_STM_usr, "STM (usr reg)", "----100--100--------------------") // v1
// Miscellaneous instructions
INST(arm_BFC, "BFC", "cccc0111110vvvvvddddvvvvv0011111") // v6T2
INST(arm_BFI, "BFI", "cccc0111110vvvvvddddvvvvv001nnnn") // v6T2
INST(arm_CLZ, "CLZ", "cccc000101101111dddd11110001mmmm") // v5
INST(arm_MOVT, "MOVT", "cccc00110100vvvvddddvvvvvvvvvvvv") // v6T2
INST(arm_MOVW, "MOVW", "cccc00110000vvvvddddvvvvvvvvvvvv") // v6T2
INST(arm_NOP, "NOP", "----0011001000001111000000000000") // v6K
INST(arm_SBFX, "SBFX", "cccc0111101wwwwwddddvvvvv101nnnn") // v6T2
INST(arm_SEL, "SEL", "cccc01101000nnnndddd11111011mmmm") // v6
INST(arm_UBFX, "UBFX", "cccc0111111wwwwwddddvvvvv101nnnn") // v6T2
// Unsigned Sum of Absolute Differences instructions
INST(arm_USAD8, "USAD8", "cccc01111000dddd1111mmmm0001nnnn") // v6
INST(arm_USADA8, "USADA8", "cccc01111000ddddaaaammmm0001nnnn") // v6
// Packing instructions
INST(arm_PKHBT, "PKHBT", "cccc01101000nnnnddddvvvvv001mmmm") // v6K
INST(arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm") // v6K
// Reversal instructions
INST(arm_RBIT, "RBIT", "cccc011011111111dddd11110011mmmm") // v6T2
INST(arm_REV, "REV", "cccc011010111111dddd11110011mmmm") // v6
INST(arm_REV16, "REV16", "cccc011010111111dddd11111011mmmm") // v6
INST(arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm") // v6
// Saturation instructions
INST(arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn") // v6
INST(arm_SSAT16, "SSAT16", "cccc01101010vvvvdddd11110011nnnn") // v6
INST(arm_USAT, "USAT", "cccc0110111vvvvvddddvvvvvr01nnnn") // v6
INST(arm_USAT16, "USAT16", "cccc01101110vvvvdddd11110011nnnn") // v6
// Divide instructions
INST(arm_SDIV, "SDIV", "cccc01110001dddd1111mmmm0001nnnn") // v7a
INST(arm_UDIV, "UDIV", "cccc01110011dddd1111mmmm0001nnnn") // v7a
// Multiply (Normal) instructions
INST(arm_MLA, "MLA", "cccc0000001Sddddaaaammmm1001nnnn") // v2
INST(arm_MLS, "MLS", "cccc00000110ddddaaaammmm1001nnnn") // v6T2
INST(arm_MUL, "MUL", "cccc0000000Sdddd0000mmmm1001nnnn") // v2
// Multiply (Long) instructions
INST(arm_SMLAL, "SMLAL", "cccc0000111Sddddaaaammmm1001nnnn") // v3M
INST(arm_SMULL, "SMULL", "cccc0000110Sddddaaaammmm1001nnnn") // v3M
INST(arm_UMAAL, "UMAAL", "cccc00000100ddddaaaammmm1001nnnn") // v6
INST(arm_UMLAL, "UMLAL", "cccc0000101Sddddaaaammmm1001nnnn") // v3M
INST(arm_UMULL, "UMULL", "cccc0000100Sddddaaaammmm1001nnnn") // v3M
// Multiply (Halfword) instructions
INST(arm_SMLALxy, "SMLALXY", "cccc00010100ddddaaaammmm1xy0nnnn") // v5xP
INST(arm_SMLAxy, "SMLAXY", "cccc00010000ddddaaaammmm1xy0nnnn") // v5xP
INST(arm_SMULxy, "SMULXY", "cccc00010110dddd0000mmmm1xy0nnnn") // v5xP
// Multiply (Word by Halfword) instructions
INST(arm_SMLAWy, "SMLAWY", "cccc00010010ddddaaaammmm1y00nnnn") // v5xP
INST(arm_SMULWy, "SMULWY", "cccc00010010dddd0000mmmm1y10nnnn") // v5xP
// Multiply (Most Significant Word) instructions
INST(arm_SMMUL, "SMMUL", "cccc01110101dddd1111mmmm00R1nnnn") // v6
INST(arm_SMMLA, "SMMLA", "cccc01110101ddddaaaammmm00R1nnnn") // v6
INST(arm_SMMLS, "SMMLS", "cccc01110101ddddaaaammmm11R1nnnn") // v6
// Multiply (Dual) instructions
INST(arm_SMLAD, "SMLAD", "cccc01110000ddddaaaammmm00M1nnnn") // v6
INST(arm_SMLALD, "SMLALD", "cccc01110100ddddaaaammmm00M1nnnn") // v6
INST(arm_SMLSD, "SMLSD", "cccc01110000ddddaaaammmm01M1nnnn") // v6
INST(arm_SMLSLD, "SMLSLD", "cccc01110100ddddaaaammmm01M1nnnn") // v6
INST(arm_SMUAD, "SMUAD", "cccc01110000dddd1111mmmm00M1nnnn") // v6
INST(arm_SMUSD, "SMUSD", "cccc01110000dddd1111mmmm01M1nnnn") // v6
// Parallel Add/Subtract (Modulo) instructions
INST(arm_SADD8, "SADD8", "cccc01100001nnnndddd11111001mmmm") // v6
INST(arm_SADD16, "SADD16", "cccc01100001nnnndddd11110001mmmm") // v6
INST(arm_SASX, "SASX", "cccc01100001nnnndddd11110011mmmm") // v6
INST(arm_SSAX, "SSAX", "cccc01100001nnnndddd11110101mmmm") // v6
INST(arm_SSUB8, "SSUB8", "cccc01100001nnnndddd11111111mmmm") // v6
INST(arm_SSUB16, "SSUB16", "cccc01100001nnnndddd11110111mmmm") // v6
INST(arm_UADD8, "UADD8", "cccc01100101nnnndddd11111001mmmm") // v6
INST(arm_UADD16, "UADD16", "cccc01100101nnnndddd11110001mmmm") // v6
INST(arm_UASX, "UASX", "cccc01100101nnnndddd11110011mmmm") // v6
INST(arm_USAX, "USAX", "cccc01100101nnnndddd11110101mmmm") // v6
INST(arm_USUB8, "USUB8", "cccc01100101nnnndddd11111111mmmm") // v6
INST(arm_USUB16, "USUB16", "cccc01100101nnnndddd11110111mmmm") // v6
// Parallel Add/Subtract (Saturating) instructions
INST(arm_QADD8, "QADD8", "cccc01100010nnnndddd11111001mmmm") // v6
INST(arm_QADD16, "QADD16", "cccc01100010nnnndddd11110001mmmm") // v6
INST(arm_QASX, "QASX", "cccc01100010nnnndddd11110011mmmm") // v6
INST(arm_QSAX, "QSAX", "cccc01100010nnnndddd11110101mmmm") // v6
INST(arm_QSUB8, "QSUB8", "cccc01100010nnnndddd11111111mmmm") // v6
INST(arm_QSUB16, "QSUB16", "cccc01100010nnnndddd11110111mmmm") // v6
INST(arm_UQADD8, "UQADD8", "cccc01100110nnnndddd11111001mmmm") // v6
INST(arm_UQADD16, "UQADD16", "cccc01100110nnnndddd11110001mmmm") // v6
INST(arm_UQASX, "UQASX", "cccc01100110nnnndddd11110011mmmm") // v6
INST(arm_UQSAX, "UQSAX", "cccc01100110nnnndddd11110101mmmm") // v6
INST(arm_UQSUB8, "UQSUB8", "cccc01100110nnnndddd11111111mmmm") // v6
INST(arm_UQSUB16, "UQSUB16", "cccc01100110nnnndddd11110111mmmm") // v6
// Parallel Add/Subtract (Halving) instructions
INST(arm_SHADD8, "SHADD8", "cccc01100011nnnndddd11111001mmmm") // v6
INST(arm_SHADD16, "SHADD16", "cccc01100011nnnndddd11110001mmmm") // v6
INST(arm_SHASX, "SHASX", "cccc01100011nnnndddd11110011mmmm") // v6
INST(arm_SHSAX, "SHSAX", "cccc01100011nnnndddd11110101mmmm") // v6
INST(arm_SHSUB8, "SHSUB8", "cccc01100011nnnndddd11111111mmmm") // v6
INST(arm_SHSUB16, "SHSUB16", "cccc01100011nnnndddd11110111mmmm") // v6
INST(arm_UHADD8, "UHADD8", "cccc01100111nnnndddd11111001mmmm") // v6
INST(arm_UHADD16, "UHADD16", "cccc01100111nnnndddd11110001mmmm") // v6
INST(arm_UHASX, "UHASX", "cccc01100111nnnndddd11110011mmmm") // v6
INST(arm_UHSAX, "UHSAX", "cccc01100111nnnndddd11110101mmmm") // v6
INST(arm_UHSUB8, "UHSUB8", "cccc01100111nnnndddd11111111mmmm") // v6
INST(arm_UHSUB16, "UHSUB16", "cccc01100111nnnndddd11110111mmmm") // v6
// Saturated Add/Subtract instructions
INST(arm_QADD, "QADD", "cccc00010000nnnndddd00000101mmmm") // v5xP
INST(arm_QSUB, "QSUB", "cccc00010010nnnndddd00000101mmmm") // v5xP
INST(arm_QDADD, "QDADD", "cccc00010100nnnndddd00000101mmmm") // v5xP
INST(arm_QDSUB, "QDSUB", "cccc00010110nnnndddd00000101mmmm") // v5xP
// Status Register Access instructions
INST(arm_CPS, "CPS", "111100010000---00000000---0-----") // v6
INST(arm_SETEND, "SETEND", "1111000100000001000000e000000000") // v6
INST(arm_MRS, "MRS", "cccc000100001111dddd000000000000") // v3
INST(arm_MSR_imm, "MSR (imm)", "cccc00110010mmmm1111rrrrvvvvvvvv") // v3
INST(arm_MSR_reg, "MSR (reg)", "cccc00010010mmmm111100000000nnnn") // v3
INST(arm_RFE, "RFE", "1111100--0-1----0000101000000000") // v6
INST(arm_SRS, "SRS", "1111100--1-0110100000101000-----") // v6
INST(arm_CLREX, "CLREX", "11110101011111111111000000011111")
INST(arm_SETEND, "SETEND", "1111000100000001000000e000000000")
INST(arm_DMB, "DMB", "1111010101111111111100000101oooo")
INST(arm_DSB, "DSB", "1111010101111111111100000100oooo")
INST(arm_ISB, "ISB", "1111010101111111111100000110oooo")
INST(arm_SEV, "SEV", "----0011001000001111000000000100")
INST(arm_SEVL, "SEVL", "----0011001000001111000000000101")
INST(arm_WFE, "WFE", "----0011001000001111000000000010")
INST(arm_WFI, "WFI", "----0011001000001111000000000011")
INST(arm_YIELD, "YIELD", "----0011001000001111000000000001")
INST(arm_NOP, "NOP", "----0011001000001111000000000000")
INST(arm_RFE, "RFE", "1111100--0-1----0000101000000000")
INST(arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm")
INST(arm_BX, "BX", "cccc000100101111111111110001mmmm")
INST(arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm")
INST(arm_NOP, "Reserved Hint", "----001100100000111100000000----")
INST(arm_MRS, "MRS", "cccc000100001111dddd000000000000")
INST(arm_SRS, "SRS", "1111100--1-0110100000101000-----")
INST(arm_CPS, "CPS", "111100010000---00000000---0-----")
INST(arm_STL, "STL", "cccc00011000nnnn111111001001tttt")
INST(arm_LDA, "LDA", "cccc00011001nnnndddd110010011111")
INST(arm_LDAEX, "LDAEX", "cccc00011001nnnndddd111010011111")
INST(arm_LDREX, "LDREX", "cccc00011001nnnndddd111110011111")
INST(arm_LDAEXD, "LDAEXD", "cccc00011011nnnndddd111010011111")
INST(arm_LDREXD, "LDREXD", "cccc00011011nnnndddd111110011111")
INST(arm_STLB, "STLB", "cccc00011100nnnn111111001001tttt")
INST(arm_LDAB, "LDAB", "cccc00011101nnnndddd110010011111")
INST(arm_LDAEXB, "LDAEXB", "cccc00011101nnnndddd111010011111")
INST(arm_LDREXB, "LDREXB", "cccc00011101nnnndddd111110011111")
INST(arm_STLH, "STLH", "cccc00011110nnnn111111001001mmmm")
INST(arm_LDAH, "LDAH", "cccc00011111nnnndddd110010011111")
INST(arm_LDAEXH, "LDAEXH", "cccc00011111nnnndddd111010011111")
INST(arm_LDREXH, "LDREXH", "cccc00011111nnnndddd111110011111")
INST(arm_CLZ, "CLZ", "cccc000101101111dddd11110001mmmm")
INST(arm_RBIT, "RBIT", "cccc011011111111dddd11110011mmmm")
INST(arm_REV, "REV", "cccc011010111111dddd11110011mmmm")
INST(arm_REV16, "REV16", "cccc011010111111dddd11111011mmmm")
INST(arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm")
INST(arm_MSR_reg, "MSR (reg)", "cccc00010010mmmm111100000000nnnn")
INST(arm_SXTB, "SXTB", "cccc011010101111ddddrr000111mmmm")
INST(arm_SXTB16, "SXTB16", "cccc011010001111ddddrr000111mmmm")
INST(arm_SXTH, "SXTH", "cccc011010111111ddddrr000111mmmm")
INST(arm_UXTB, "UXTB", "cccc011011101111ddddrr000111mmmm")
INST(arm_UXTB16, "UXTB16", "cccc011011001111ddddrr000111mmmm")
INST(arm_UXTH, "UXTH", "cccc011011111111ddddrr000111mmmm")
INST(arm_UDF, "UDF", "111001111111------------1111----")
INST(arm_NOP, "Reserved Hint", "----0011001000001111------------")
INST(arm_SWP, "SWP", "cccc00010000nnnntttt00001001uuuu")
INST(arm_SWPB, "SWPB", "cccc00010100nnnntttt00001001uuuu")
INST(arm_STLEX, "STLEX", "cccc00011000nnnndddd11101001tttt")
INST(arm_STREX, "STREX", "cccc00011000nnnndddd11111001mmmm")
INST(arm_STLEXD, "STLEXD", "cccc00011010nnnndddd11101001mmmm")
INST(arm_STREXD, "STREXD", "cccc00011010nnnndddd11111001mmmm")
INST(arm_STLEXB, "STLEXB", "cccc00011100nnnndddd11101001mmmm")
INST(arm_STREXB, "STREXB", "cccc00011100nnnndddd11111001mmmm")
INST(arm_STLEXH, "STLEXH", "cccc00011110nnnndddd11101001mmmm")
INST(arm_STREXH, "STREXH", "cccc00011110nnnndddd11111001mmmm")
INST(arm_SEL, "SEL", "cccc01101000nnnndddd11111011mmmm")
INST(arm_USAD8, "USAD8", "cccc01111000dddd1111mmmm0001nnnn")
INST(arm_SSAT16, "SSAT16", "cccc01101010vvvvdddd11110011nnnn")
INST(arm_USAT16, "USAT16", "cccc01101110vvvvdddd11110011nnnn")
INST(arm_SDIV, "SDIV", "cccc01110001dddd1111mmmm0001nnnn")
INST(arm_UDIV, "UDIV", "cccc01110011dddd1111mmmm0001nnnn")
INST(arm_SADD8, "SADD8", "cccc01100001nnnndddd11111001mmmm")
INST(arm_SADD16, "SADD16", "cccc01100001nnnndddd11110001mmmm")
INST(arm_SASX, "SASX", "cccc01100001nnnndddd11110011mmmm")
INST(arm_SSAX, "SSAX", "cccc01100001nnnndddd11110101mmmm")
INST(arm_SSUB8, "SSUB8", "cccc01100001nnnndddd11111111mmmm")
INST(arm_SSUB16, "SSUB16", "cccc01100001nnnndddd11110111mmmm")
INST(arm_UADD8, "UADD8", "cccc01100101nnnndddd11111001mmmm")
INST(arm_UADD16, "UADD16", "cccc01100101nnnndddd11110001mmmm")
INST(arm_UASX, "UASX", "cccc01100101nnnndddd11110011mmmm")
INST(arm_USAX, "USAX", "cccc01100101nnnndddd11110101mmmm")
INST(arm_USUB8, "USUB8", "cccc01100101nnnndddd11111111mmmm")
INST(arm_USUB16, "USUB16", "cccc01100101nnnndddd11110111mmmm")
INST(arm_QADD8, "QADD8", "cccc01100010nnnndddd11111001mmmm")
INST(arm_QADD16, "QADD16", "cccc01100010nnnndddd11110001mmmm")
INST(arm_QASX, "QASX", "cccc01100010nnnndddd11110011mmmm")
INST(arm_QSAX, "QSAX", "cccc01100010nnnndddd11110101mmmm")
INST(arm_QSUB8, "QSUB8", "cccc01100010nnnndddd11111111mmmm")
INST(arm_QSUB16, "QSUB16", "cccc01100010nnnndddd11110111mmmm")
INST(arm_UQADD8, "UQADD8", "cccc01100110nnnndddd11111001mmmm")
INST(arm_UQADD16, "UQADD16", "cccc01100110nnnndddd11110001mmmm")
INST(arm_UQASX, "UQASX", "cccc01100110nnnndddd11110011mmmm")
INST(arm_UQSAX, "UQSAX", "cccc01100110nnnndddd11110101mmmm")
INST(arm_UQSUB8, "UQSUB8", "cccc01100110nnnndddd11111111mmmm")
INST(arm_UQSUB16, "UQSUB16", "cccc01100110nnnndddd11110111mmmm")
INST(arm_SHADD8, "SHADD8", "cccc01100011nnnndddd11111001mmmm")
INST(arm_SHADD16, "SHADD16", "cccc01100011nnnndddd11110001mmmm")
INST(arm_SHASX, "SHASX", "cccc01100011nnnndddd11110011mmmm")
INST(arm_SHSAX, "SHSAX", "cccc01100011nnnndddd11110101mmmm")
INST(arm_SHSUB8, "SHSUB8", "cccc01100011nnnndddd11111111mmmm")
INST(arm_SHSUB16, "SHSUB16", "cccc01100011nnnndddd11110111mmmm")
INST(arm_UHADD8, "UHADD8", "cccc01100111nnnndddd11111001mmmm")
INST(arm_UHADD16, "UHADD16", "cccc01100111nnnndddd11110001mmmm")
INST(arm_UHASX, "UHASX", "cccc01100111nnnndddd11110011mmmm")
INST(arm_UHSAX, "UHSAX", "cccc01100111nnnndddd11110101mmmm")
INST(arm_UHSUB8, "UHSUB8", "cccc01100111nnnndddd11111111mmmm")
INST(arm_UHSUB16, "UHSUB16", "cccc01100111nnnndddd11110111mmmm")
INST(arm_QADD, "QADD", "cccc00010000nnnndddd00000101mmmm")
INST(arm_QSUB, "QSUB", "cccc00010010nnnndddd00000101mmmm")
INST(arm_QDADD, "QDADD", "cccc00010100nnnndddd00000101mmmm")
INST(arm_QDSUB, "QDSUB", "cccc00010110nnnndddd00000101mmmm")
INST(arm_PLD_reg, "PLD (reg)", "11110111uz01nnnn1111iiiiitt0mmmm")
INST(arm_LDRHT, "LDRHT (A1)", "----0000-1111111--------1011----")
INST(arm_LDRHT, "LDRHT (A2)", "----0000-011--------00001011----")
INST(arm_LDRSBT, "LDRSBT (A2)", "----0000-011--------00001101----")
INST(arm_LDRSHT, "LDRSHT (A2)", "----0000-011--------00001111----")
INST(arm_STRHT, "STRHT (A2)", "----0000-010--------00001011----")
INST(arm_LDRD_lit, "LDRD (lit)", "cccc0001u1001111ttttvvvv1101vvvv")
INST(arm_LDRSB_lit, "LDRSB (lit)", "cccc0001u1011111ttttvvvv1101vvvv")
INST(arm_LDRSH_lit, "LDRSH (lit)", "cccc0001u1011111ttttvvvv1111vvvv")
INST(arm_MUL, "MUL", "cccc0000000Sdddd0000mmmm1001nnnn")
INST(arm_SMULWy, "SMULWY", "cccc00010010dddd0000mmmm1y10nnnn")
INST(arm_SMMUL, "SMMUL", "cccc01110101dddd1111mmmm00R1nnnn")
INST(arm_SMUAD, "SMUAD", "cccc01110000dddd1111mmmm00M1nnnn")
INST(arm_SMUSD, "SMUSD", "cccc01110000dddd1111mmmm01M1nnnn")
INST(arm_CRC32, "CRC32", "cccc00010zz0nnnndddd00000100mmmm")
INST(arm_CRC32C, "CRC32C", "cccc00010zz0nnnndddd00100100mmmm")
INST(arm_CMN_rsr, "CMN (rsr)", "cccc00010111nnnn0000ssss0rr1mmmm")
INST(arm_CMP_rsr, "CMP (rsr)", "cccc00010101nnnn0000ssss0rr1mmmm")
INST(arm_TEQ_rsr, "TEQ (rsr)", "cccc00010011nnnn0000ssss0rr1mmmm")
INST(arm_TST_rsr, "TST (rsr)", "cccc00010001nnnn0000ssss0rr1mmmm")
INST(arm_SXTAB, "SXTAB", "cccc01101010nnnnddddrr000111mmmm")
INST(arm_SXTAB16, "SXTAB16", "cccc01101000nnnnddddrr000111mmmm")
INST(arm_SXTAH, "SXTAH", "cccc01101011nnnnddddrr000111mmmm")
INST(arm_UXTAB, "UXTAB", "cccc01101110nnnnddddrr000111mmmm")
INST(arm_UXTAB16, "UXTAB16", "cccc01101100nnnnddddrr000111mmmm")
INST(arm_UXTAH, "UXTAH", "cccc01101111nnnnddddrr000111mmmm")
INST(arm_PLD_imm, "PLD (imm)", "11110101uz01nnnn1111iiiiiiiiiiii")
INST(arm_BFC, "BFC", "cccc0111110vvvvvddddvvvvv0011111")
INST(arm_SMULxy, "SMULXY", "cccc00010110dddd0000mmmm1xy0nnnn")
INST(arm_CMN_reg, "CMN (reg)", "cccc00010111nnnn0000vvvvvrr0mmmm")
INST(arm_CMP_reg, "CMP (reg)", "cccc00010101nnnn0000vvvvvrr0mmmm")
INST(arm_MOV_rsr, "MOV (rsr)", "cccc0001101S0000ddddssss0rr1mmmm")
INST(arm_MVN_rsr, "MVN (rsr)", "cccc0001111S0000ddddssss0rr1mmmm")
INST(arm_TEQ_reg, "TEQ (reg)", "cccc00010011nnnn0000vvvvvrr0mmmm")
INST(arm_TST_reg, "TST (reg)", "cccc00010001nnnn0000vvvvvrr0mmmm")
INST(arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnntttt00001101mmmm")
INST(arm_LDRH_lit, "LDRH (lit)", "cccc000pu1w11111ttttvvvv1011vvvv")
INST(arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnntttt00001011mmmm")
INST(arm_LDRSB_reg, "LDRSB (reg)", "cccc000pu0w1nnnntttt00001101mmmm")
INST(arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnntttt00001111mmmm")
INST(arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnntttt00001111mmmm")
INST(arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnntttt00001011mmmm")
INST(arm_CMN_imm, "CMN (imm)", "cccc00110111nnnn0000rrrrvvvvvvvv")
INST(arm_CMP_imm, "CMP (imm)", "cccc00110101nnnn0000rrrrvvvvvvvv")
INST(arm_MOV_reg, "MOV (reg)", "cccc0001101S0000ddddvvvvvrr0mmmm")
INST(arm_MVN_reg, "MVN (reg)", "cccc0001111S0000ddddvvvvvrr0mmmm")
INST(arm_TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv")
INST(arm_TST_imm, "TST (imm)", "cccc00110001nnnn0000rrrrvvvvvvvv")
INST(arm_BKPT, "BKPT", "cccc00010010vvvvvvvvvvvv0111vvvv")
INST(arm_USADA8, "USADA8", "cccc01111000ddddaaaammmm0001nnnn")
INST(arm_MLS, "MLS", "cccc00000110ddddaaaammmm1001nnnn")
INST(arm_UMAAL, "UMAAL", "cccc00000100ddddaaaammmm1001nnnn")
INST(arm_MSR_imm, "MSR (imm)", "cccc00110010mmmm1111rrrrvvvvvvvv")
INST(arm_MOV_imm, "MOV (imm)", "cccc0011101S0000ddddrrrrvvvvvvvv")
INST(arm_MVN_imm, "MVN (imm)", "cccc0011111S0000ddddrrrrvvvvvvvv")
INST(arm_LDRHT, "LDRHT (A1)", "----0000-111------------1011----")
INST(arm_LDRSBT, "LDRSBT (A1)", "----0000-111------------1101----")
INST(arm_LDRSHT, "LDRSHT (A1)", "----0000-111------------1111----")
INST(arm_STRHT, "STRHT (A1)", "----0000-110------------1011----")
INST(arm_LDR_lit, "LDR (lit)", "cccc0101u0011111ttttvvvvvvvvvvvv")
INST(arm_LDRB_lit, "LDRB (lit)", "cccc0101u1011111ttttvvvvvvvvvvvv")
INST(arm_PKHBT, "PKHBT", "cccc01101000nnnnddddvvvvv001mmmm")
INST(arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm")
INST(arm_MLA, "MLA", "cccc0000001Sddddaaaammmm1001nnnn")
INST(arm_SMLAL, "SMLAL", "cccc0000111Sddddaaaammmm1001nnnn")
INST(arm_SMULL, "SMULL", "cccc0000110Sddddaaaammmm1001nnnn")
INST(arm_UMLAL, "UMLAL", "cccc0000101Sddddaaaammmm1001nnnn")
INST(arm_UMULL, "UMULL", "cccc0000100Sddddaaaammmm1001nnnn")
INST(arm_SMLAWy, "SMLAWY", "cccc00010010ddddaaaammmm1y00nnnn")
INST(arm_SMMLA, "SMMLA", "cccc01110101ddddaaaammmm00R1nnnn")
INST(arm_SMMLS, "SMMLS", "cccc01110101ddddaaaammmm11R1nnnn")
INST(arm_SMLAD, "SMLAD", "cccc01110000ddddaaaammmm00M1nnnn")
INST(arm_SMLALD, "SMLALD", "cccc01110100ddddaaaammmm00M1nnnn")
INST(arm_SMLSD, "SMLSD", "cccc01110000ddddaaaammmm01M1nnnn")
INST(arm_SMLSLD, "SMLSLD", "cccc01110100ddddaaaammmm01M1nnnn")
INST(arm_BFI, "BFI", "cccc0111110vvvvvddddvvvvv001nnnn")
INST(arm_SBFX, "SBFX", "cccc0111101wwwwwddddvvvvv101nnnn")
INST(arm_UBFX, "UBFX", "cccc0111111wwwwwddddvvvvv101nnnn")
INST(arm_SMLALxy, "SMLALXY", "cccc00010100ddddaaaammmm1xy0nnnn")
INST(arm_SMLAxy, "SMLAXY", "cccc00010000ddddaaaammmm1xy0nnnn")
INST(arm_ADC_rsr, "ADC (rsr)", "cccc0000101Snnnnddddssss0rr1mmmm")
INST(arm_ADD_rsr, "ADD (rsr)", "cccc0000100Snnnnddddssss0rr1mmmm")
INST(arm_AND_rsr, "AND (rsr)", "cccc0000000Snnnnddddssss0rr1mmmm")
INST(arm_BIC_rsr, "BIC (rsr)", "cccc0001110Snnnnddddssss0rr1mmmm")
INST(arm_EOR_rsr, "EOR (rsr)", "cccc0000001Snnnnddddssss0rr1mmmm")
INST(arm_ORR_rsr, "ORR (rsr)", "cccc0001100Snnnnddddssss0rr1mmmm")
INST(arm_RSB_rsr, "RSB (rsr)", "cccc0000011Snnnnddddssss0rr1mmmm")
INST(arm_RSC_rsr, "RSC (rsr)", "cccc0000111Snnnnddddssss0rr1mmmm")
INST(arm_SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm")
INST(arm_SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm")
INST(arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnttttvvvv1101vvvv")
INST(arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnttttvvvv1011vvvv")
INST(arm_LDRSB_imm, "LDRSB (imm)", "cccc000pu1w1nnnnttttvvvv1101vvvv")
INST(arm_LDRSH_imm, "LDRSH (imm)", "cccc000pu1w1nnnnttttvvvv1111vvvv")
INST(arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnttttvvvv1111vvvv")
INST(arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnttttvvvv1011vvvv")
INST(arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn")
INST(arm_USAT, "USAT", "cccc0110111vvvvvddddvvvvvr01nnnn")
INST(arm_MCRR, "MCRR", "cccc11000100uuuuttttppppooooMMMM")
INST(arm_MRRC, "MRRC", "cccc11000101uuuuttttppppooooMMMM")
INST(arm_ADC_reg, "ADC (reg)", "cccc0000101Snnnnddddvvvvvrr0mmmm")
INST(arm_ADD_reg, "ADD (reg)", "cccc0000100Snnnnddddvvvvvrr0mmmm")
INST(arm_AND_reg, "AND (reg)", "cccc0000000Snnnnddddvvvvvrr0mmmm")
INST(arm_BIC_reg, "BIC (reg)", "cccc0001110Snnnnddddvvvvvrr0mmmm")
INST(arm_EOR_reg, "EOR (reg)", "cccc0000001Snnnnddddvvvvvrr0mmmm")
INST(arm_ORR_reg, "ORR (reg)", "cccc0001100Snnnnddddvvvvvrr0mmmm")
INST(arm_RSB_reg, "RSB (reg)", "cccc0000011Snnnnddddvvvvvrr0mmmm")
INST(arm_RSC_reg, "RSC (reg)", "cccc0000111Snnnnddddvvvvvrr0mmmm")
INST(arm_SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm")
INST(arm_SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm")
INST(arm_LDRBT, "LDRBT (A2)", "----0110-111---------------0----")
INST(arm_LDRT, "LDRT (A2)", "----0110-011---------------0----")
INST(arm_STRBT, "STRBT (A2)", "----0110-110---------------0----")
INST(arm_STRT, "STRT (A2)", "----0110-010---------------0----")
INST(arm_MOVT, "MOVT", "cccc00110100vvvvddddvvvvvvvvvvvv")
INST(arm_MOVW, "MOVW", "cccc00110000vvvvddddvvvvvvvvvvvv")
INST(arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv")
INST(arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv")
INST(arm_ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv")
INST(arm_AND_imm, "AND (imm)", "cccc0010000Snnnnddddrrrrvvvvvvvv")
INST(arm_BIC_imm, "BIC (imm)", "cccc0011110Snnnnddddrrrrvvvvvvvv")
INST(arm_EOR_imm, "EOR (imm)", "cccc0010001Snnnnddddrrrrvvvvvvvv")
INST(arm_ORR_imm, "ORR (imm)", "cccc0011100Snnnnddddrrrrvvvvvvvv")
INST(arm_RSB_imm, "RSB (imm)", "cccc0010011Snnnnddddrrrrvvvvvvvv")
INST(arm_RSC_imm, "RSC (imm)", "cccc0010111Snnnnddddrrrrvvvvvvvv")
INST(arm_SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv")
INST(arm_SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv")
INST(arm_LDRBT, "LDRBT (A1)", "----0100-111--------------------")
INST(arm_LDRT, "LDRT (A1)", "----0100-011--------------------")
INST(arm_STRBT, "STRBT (A1)", "----0100-110--------------------")
INST(arm_STRT, "STRT (A1)", "----0100-010--------------------")
INST(arm_LDM, "LDM", "cccc100010w1nnnnxxxxxxxxxxxxxxxx")
INST(arm_LDMDA, "LDMDA", "cccc100000w1nnnnxxxxxxxxxxxxxxxx")
INST(arm_LDMDB, "LDMDB", "cccc100100w1nnnnxxxxxxxxxxxxxxxx")
INST(arm_LDMIB, "LDMIB", "cccc100110w1nnnnxxxxxxxxxxxxxxxx")
INST(arm_STM, "STM", "cccc100010w0nnnnxxxxxxxxxxxxxxxx")
INST(arm_STMDA, "STMDA", "cccc100000w0nnnnxxxxxxxxxxxxxxxx")
INST(arm_STMDB, "STMDB", "cccc100100w0nnnnxxxxxxxxxxxxxxxx")
INST(arm_STMIB, "STMIB", "cccc100110w0nnnnxxxxxxxxxxxxxxxx")
INST(arm_MCR, "MCR", "cccc1110ooo0NNNNttttppppooo1MMMM")
INST(arm_MRC, "MRC", "cccc1110ooo1NNNNttttppppooo1MMMM")
INST(arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnttttvvvvvrr0mmmm")
INST(arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnttttvvvvvrr0mmmm")
INST(arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnttttvvvvvrr0mmmm")
INST(arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnttttvvvvvrr0mmmm")
INST(arm_LDM_usr, "LDM (usr reg)", "----100--101--------------------")
INST(arm_LDM_eret, "LDM (exce ret)", "----100--1-1----1---------------")
INST(arm_STM_usr, "STM (usr reg)", "----100--100--------------------")
INST(arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM")
INST(arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnttttvvvvvvvvvvvv")
INST(arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnttttvvvvvvvvvvvv")
INST(arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnttttvvvvvvvvvvvv")
INST(arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnttttvvvvvvvvvvvv")
INST(arm_B, "B", "cccc1010vvvvvvvvvvvvvvvvvvvvvvvv")
INST(arm_BL, "BL", "cccc1011vvvvvvvvvvvvvvvvvvvvvvvv")
INST(arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv")
INST(arm_STC, "STC", "cccc110pudw0nnnnDDDDppppvvvvvvvv")
INST(arm_SVC, "SVC", "cccc1111vvvvvvvvvvvvvvvvvvvvvvvv")

View file

@ -27,50 +27,12 @@ template<typename Visitor>
using ASIMDMatcher = Decoder::Matcher<Visitor, u32>;
template<typename V>
std::vector<ASIMDMatcher<V>> GetASIMDDecodeTable() noexcept {
std::vector<std::pair<const char*, ASIMDMatcher<V>>> table = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
static std::optional<std::reference_wrapper<const ASIMDMatcher<V>>> DecodeASIMD(u32 instruction) noexcept {
alignas(64) static const auto table = std::array{
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./asimd.inc"
#undef INST
};
// Exceptions to the rule of thumb.
const std::set<std::string> comes_first{
"VBIC, VMOV, VMVN, VORR (immediate)",
"VEXT",
"VTBL",
"VTBX",
"VDUP (scalar)",
};
const std::set<std::string> comes_last{
"VMLA (scalar)",
"VMLAL (scalar)",
"VQDMLAL/VQDMLSL (scalar)",
"VMUL (scalar)",
"VMULL (scalar)",
"VQDMULL (scalar)",
"VQDMULH (scalar)",
"VQRDMULH (scalar)",
};
const auto sort_begin = std::stable_partition(table.begin(), table.end(), [&](const auto& e) {
return comes_first.count(e.first) > 0;
});
const auto sort_end = std::stable_partition(table.begin(), table.end(), [&](const auto& e) {
return comes_last.count(e.first) == 0;
});
// If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(sort_begin, sort_end, [](const auto& a, const auto& b) {
return mcl::bit::count_ones(a.second.GetMask()) > mcl::bit::count_ones(b.second.GetMask());
});
std::vector<ASIMDMatcher<V>> final_table;
std::transform(table.cbegin(), table.cend(), std::back_inserter(final_table), [](auto const& e) {
return e.second;
});
return final_table;
}
template<typename V>
std::optional<std::reference_wrapper<const ASIMDMatcher<V>>> DecodeASIMD(u32 instruction) noexcept {
alignas(64) static const auto table = GetASIMDDecodeTable<V>();
auto iter = std::find_if(table.begin(), table.end(), [instruction](const auto& matcher) {
return matcher.Matches(instruction);
});
@ -78,7 +40,7 @@ std::optional<std::reference_wrapper<const ASIMDMatcher<V>>> DecodeASIMD(u32 ins
}
template<typename V>
std::optional<std::string_view> GetNameASIMD(u32 inst) noexcept {
static std::optional<std::string_view> GetNameASIMD(u32 inst) noexcept {
std::vector<std::pair<std::string_view, ASIMDMatcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./asimd.inc"

View file

@ -1,172 +1,151 @@
// Three registers of the same length
INST(asimd_VHADD, "VHADD", "1111001U0Dzznnnndddd0000NQM0mmmm") // ASIMD
INST(asimd_VQADD, "VQADD", "1111001U0Dzznnnndddd0000NQM1mmmm") // ASIMD
INST(asimd_VRHADD, "VRHADD", "1111001U0Dzznnnndddd0001NQM0mmmm") // ASIMD
INST(asimd_VAND_reg, "VAND (register)", "111100100D00nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VBIC_reg, "VBIC (register)", "111100100D01nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VORR_reg, "VORR (register)", "111100100D10nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VORN_reg, "VORN (register)", "111100100D11nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VEOR_reg, "VEOR (register)", "111100110D00nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VBSL, "VBSL", "111100110D01nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VBIT, "VBIT", "111100110D10nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VBIF, "VBIF", "111100110D11nnnndddd0001NQM1mmmm") // ASIMD
INST(asimd_VHSUB, "VHSUB", "1111001U0Dzznnnndddd0010NQM0mmmm") // ASIMD
INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd0010NQM1mmmm") // ASIMD
INST(asimd_VCGT_reg, "VCGT (register)", "1111001U0Dzznnnndddd0011NQM0mmmm") // ASIMD
INST(asimd_VCGE_reg, "VCGE (register)", "1111001U0Dzznnnndddd0011NQM1mmmm") // ASIMD
INST(asimd_VSHL_reg, "VSHL (register)", "1111001U0Dzznnnndddd0100NQM0mmmm") // ASIMD
INST(asimd_VQSHL_reg, "VQSHL (register)", "1111001U0Dzznnnndddd0100NQM1mmmm") // ASIMD
INST(asimd_VRSHL, "VRSHL", "1111001U0Dzznnnndddd0101NQM0mmmm") // ASIMD
//INST(asimd_VQRSHL, "VQRSHL", "1111001U0-CC--------0101---1----") // ASIMD
INST(asimd_VMAX, "VMAX/VMIN (integer)", "1111001U0Dzznnnnmmmm0110NQMommmm") // ASIMD
INST(asimd_VABD, "VABD", "1111001U0Dzznnnndddd0111NQM0mmmm") // ASIMD
INST(asimd_VABA, "VABA", "1111001U0Dzznnnndddd0111NQM1mmmm") // ASIMD
INST(asimd_VADD_int, "VADD (integer)", "111100100Dzznnnndddd1000NQM0mmmm") // ASIMD
INST(asimd_VSUB_int, "VSUB (integer)", "111100110Dzznnnndddd1000NQM0mmmm") // ASIMD
INST(asimd_VTST, "VTST", "111100100Dzznnnndddd1000NQM1mmmm") // ASIMD
INST(asimd_VCEQ_reg, "VCEG (register)", "111100110Dzznnnndddd1000NQM1mmmm") // ASIMD
INST(asimd_VMLA, "VMLA/VMLS", "1111001o0Dzznnnndddd1001NQM0mmmm") // ASIMD
INST(asimd_VMUL, "VMUL", "1111001P0Dzznnnndddd1001NQM1mmmm") // ASIMD
INST(asimd_VPMAX_int, "VPMAX/VPMIN (integer)", "1111001U0Dzznnnndddd1010NQMommmm") // ASIMD
INST(v8_VMAXNM, "VMAXNM", "111100110D0znnnndddd1111NQM1mmmm") // v8
INST(v8_VMINNM, "VMINNM", "111100110D1znnnndddd1111NQM1mmmm") // v8
INST(asimd_VQDMULH, "VQDMULH", "111100100Dzznnnndddd1011NQM0mmmm") // ASIMD
INST(asimd_VQRDMULH, "VQRDMULH", "111100110Dzznnnndddd1011NQM0mmmm") // ASIMD
INST(asimd_VPADD, "VPADD", "111100100Dzznnnndddd1011NQM1mmmm") // ASIMD
INST(asimd_VFMA, "VFMA", "111100100D0znnnndddd1100NQM1mmmm") // ASIMD
INST(asimd_VFMS, "VFMS", "111100100D1znnnndddd1100NQM1mmmm") // ASIMD
INST(asimd_VADD_float, "VADD (floating-point)", "111100100D0znnnndddd1101NQM0mmmm") // ASIMD
INST(asimd_VSUB_float, "VSUB (floating-point)", "111100100D1znnnndddd1101NQM0mmmm") // ASIMD
INST(asimd_VPADD_float, "VPADD (floating-point)", "111100110D0znnnndddd1101NQM0mmmm") // ASIMD
INST(asimd_VABD_float, "VABD (floating-point)", "111100110D1znnnndddd1101NQM0mmmm") // ASIMD
INST(asimd_VMLA_float, "VMLA (floating-point)", "111100100D0znnnndddd1101NQM1mmmm") // ASIMD
INST(asimd_VMLS_float, "VMLS (floating-point)", "111100100D1znnnndddd1101NQM1mmmm") // ASIMD
INST(asimd_VMUL_float, "VMUL (floating-point)", "111100110D0znnnndddd1101NQM1mmmm") // ASIMD
INST(asimd_VCEQ_reg_float, "VCEQ (register)", "111100100D0znnnndddd1110NQM0mmmm") // ASIMD
INST(asimd_VCGE_reg_float, "VCGE (register)", "111100110D0znnnndddd1110NQM0mmmm") // ASIMD
INST(asimd_VCGT_reg_float, "VCGT (register)", "111100110D1znnnndddd1110NQM0mmmm") // ASIMD
INST(asimd_VACGE, "VACGE", "111100110Doznnnndddd1110NQM1mmmm") // ASIMD
INST(asimd_VMAX_float, "VMAX (floating-point)", "111100100D0znnnndddd1111NQM0mmmm") // ASIMD
INST(asimd_VMIN_float, "VMIN (floating-point)", "111100100D1znnnndddd1111NQM0mmmm") // ASIMD
INST(asimd_VPMAX_float, "VPMAX (floating-point)", "111100110D0znnnndddd1111NQM0mmmm") // ASIMD
INST(asimd_VPMIN_float, "VPMIN (floating-point)", "111100110D1znnnndddd1111NQM0mmmm") // ASIMD
INST(asimd_VRECPS, "VRECPS", "111100100D0znnnndddd1111NQM1mmmm") // ASIMD
INST(asimd_VRSQRTS, "VRSQRTS", "111100100D1znnnndddd1111NQM1mmmm") // ASIMD
INST(v8_SHA256H, "SHA256H", "111100110D00nnnndddd1100NQM0mmmm") // v8
INST(v8_SHA256H2, "SHA256H2", "111100110D01nnnndddd1100NQM0mmmm") // v8
INST(v8_SHA256SU1, "SHA256SU1", "111100110D10nnnndddd1100NQM0mmmm") // v8
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// DO NOT REORDER
// Three registers of different lengths
INST(asimd_VADDL, "VADDL/VADDW", "1111001U1Dzznnnndddd000oN0M0mmmm") // ASIMD
INST(asimd_VSUBL, "VSUBL/VSUBW", "1111001U1Dzznnnndddd001oN0M0mmmm") // ASIMD
//INST(asimd_VADDHN, "VADDHN", "111100101-----------0100-0-0----") // ASIMD
//INST(asimd_VRADDHN, "VRADDHN", "111100111-----------0100-0-0----") // ASIMD
INST(asimd_VABAL, "VABAL", "1111001U1Dzznnnndddd0101N0M0mmmm") // ASIMD
//INST(asimd_VSUBHN, "VSUBHN", "111100101-----------0110-0-0----") // ASIMD
//INST(asimd_VRSUBHN, "VRSUBHN", "111100111-----------0110-0-0----") // ASIMD
INST(asimd_VABDL, "VABDL", "1111001U1Dzznnnndddd0111N0M0mmmm") // ASIMD
INST(asimd_VMLAL, "VMLAL/VMLSL", "1111001U1Dzznnnndddd10o0N0M0mmmm") // ASIMD
//INST(asimd_VQDMLAL, "VQDMLAL", "111100101-----------10-1-0-0----") // ASIMD
INST(asimd_VMULL, "VMULL", "1111001U1Dzznnnndddd11P0N0M0mmmm") // ASIMD
//INST(asimd_VQDMULL, "VQDMULL", "111100101-----------1101-0-0----") // ASIMD
// Two registers and a scalar
INST(asimd_VMLA_scalar, "VMLA (scalar)", "1111001Q1Dzznnnndddd0o0FN1M0mmmm") // ASIMD
INST(asimd_VMLAL_scalar, "VMLAL (scalar)", "1111001U1dzznnnndddd0o10N1M0mmmm") // ASIMD
//INST(asimd_VQDMLAL_scalar, "VQDMLAL/VQDMLSL (scalar)", "111100101-BB--------0x11-1-0----") // ASIMD
INST(asimd_VMUL_scalar, "VMUL (scalar)", "1111001Q1Dzznnnndddd100FN1M0mmmm") // ASIMD
INST(asimd_VMULL_scalar, "VMULL (scalar)", "1111001U1Dzznnnndddd1010N1M0mmmm") // ASIMD
INST(asimd_VQDMULL_scalar, "VQDMULL (scalar)", "111100101Dzznnnndddd1011N1M0mmmm") // ASIMD
INST(asimd_VQDMULH_scalar, "VQDMULH (scalar)", "1111001Q1Dzznnnndddd1100N1M0mmmm") // ASIMD
INST(asimd_VQRDMULH_scalar, "VQRDMULH (scalar)", "1111001Q1Dzznnnndddd1101N1M0mmmm") // ASIMD
// Two registers and a shift amount
INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD
INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm") // ASIMD
INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm") // ASIMD
INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm") // ASIMD
INST(asimd_VSRI, "VSRI", "111100111Diiiiiidddd0100LQM1mmmm") // ASIMD
INST(asimd_VSHL, "VSHL", "111100101Diiiiiidddd0101LQM1mmmm") // ASIMD
INST(asimd_VSLI, "VSLI", "111100111Diiiiiidddd0101LQM1mmmm") // ASIMD
INST(asimd_VQSHL, "VQSHL" , "1111001U1Diiiiiidddd011oLQM1mmmm") // ASIMD
INST(asimd_VSHRN, "VSHRN", "111100101Diiiiiidddd100000M1mmmm") // ASIMD
INST(asimd_VRSHRN, "VRSHRN", "111100101Diiiiiidddd100001M1mmmm") // ASIMD
INST(asimd_VQSHRUN, "VQSHRUN", "111100111Diiiiiidddd100000M1mmmm") // ASIMD
INST(asimd_VQRSHRUN, "VQRSHRUN", "111100111Diiiiiidddd100001M1mmmm") // ASIMD
INST(asimd_VQSHRN, "VQSHRN", "1111001U1Diiiiiidddd100100M1mmmm") // ASIMD
INST(asimd_VQRSHRN, "VQRSHRN", "1111001U1Diiiiiidddd100101M1mmmm") // ASIMD
INST(asimd_VSHLL, "VSHLL", "1111001U1Diiiiiidddd101000M1mmmm") // ASIMD
INST(asimd_VCVT_fixed, "VCVT (fixed-point)", "1111001U1Diiiiiidddd111o0QM1mmmm") // ASIMD
// Two registers, miscellaneous
INST(asimd_VREV, "VREV{16,32,64}", "111100111D11zz00dddd000ooQM0mmmm") // ASIMD
INST(asimd_VPADDL, "VPADDL", "111100111D11zz00dddd0010oQM0mmmm") // ASIMD
INST(asimd_VCLS, "VCLS", "111100111D11zz00dddd01000QM0mmmm") // ASIMD
INST(asimd_VCLZ, "VCLZ", "111100111D11zz00dddd01001QM0mmmm") // ASIMD
INST(asimd_VCNT, "VCNT", "111100111D11zz00dddd01010QM0mmmm") // ASIMD
INST(asimd_VMVN_reg, "VMVN_reg", "111100111D11zz00dddd01011QM0mmmm") // ASIMD
INST(asimd_VPADAL, "VPADAL", "111100111D11zz00dddd0110oQM0mmmm") // ASIMD
INST(asimd_VQABS, "VQABS", "111100111D11zz00dddd01110QM0mmmm") // ASIMD
INST(asimd_VQNEG, "VQNEG", "111100111D11zz00dddd01111QM0mmmm") // ASIMD
INST(asimd_VCGT_zero, "VCGT (zero)", "111100111D11zz01dddd0F000QM0mmmm") // ASIMD
INST(asimd_VCGE_zero, "VCGE (zero)", "111100111D11zz01dddd0F001QM0mmmm") // ASIMD
INST(asimd_VCEQ_zero, "VCEQ (zero)", "111100111D11zz01dddd0F010QM0mmmm") // ASIMD
INST(asimd_VCLE_zero, "VCLE (zero)", "111100111D11zz01dddd0F011QM0mmmm") // ASIMD
INST(asimd_VCLT_zero, "VCLT (zero)", "111100111D11zz01dddd0F100QM0mmmm") // ASIMD
INST(arm_UDF, "UNALLOCATED", "111100111-11--01----01101--0----") // v8
INST(asimd_VABS, "VABS", "111100111D11zz01dddd0F110QM0mmmm") // ASIMD
INST(asimd_VNEG, "VNEG", "111100111D11zz01dddd0F111QM0mmmm") // ASIMD
INST(asimd_VSWP, "VSWP", "111100111D110010dddd00000QM0mmmm") // ASIMD
INST(arm_UDF, "UNALLOCATED", "111100111-11--10----00000--0----") // ASIMD
INST(asimd_VTRN, "VTRN", "111100111D11zz10dddd00001QM0mmmm") // ASIMD
INST(asimd_VUZP, "VUZP", "111100111D11zz10dddd00010QM0mmmm") // ASIMD
INST(asimd_VZIP, "VZIP", "111100111D11zz10dddd00011QM0mmmm") // ASIMD
INST(asimd_VMOVN, "VMOVN", "111100111D11zz10dddd001000M0mmmm") // ASIMD
INST(asimd_VQMOVUN, "VQMOVUN", "111100111D11zz10dddd001001M0mmmm") // ASIMD
INST(asimd_VQMOVN, "VQMOVN", "111100111D11zz10dddd00101oM0mmmm") // ASIMD
INST(asimd_VSHLL_max, "VSHLL_max", "111100111D11zz10dddd001100M0mmmm") // ASIMD
INST(v8_VRINTN, "VRINTN", "111100111D11zz10dddd01000QM0mmmm") // v8
INST(v8_VRINTX, "VRINTX", "111100111D11zz10dddd01001QM0mmmm") // v8
INST(v8_VRINTA, "VRINTA", "111100111D11zz10dddd01010QM0mmmm") // v8
INST(v8_VRINTZ, "VRINTZ", "111100111D11zz10dddd01011QM0mmmm") // v8
INST(v8_VRINTM, "VRINTM", "111100111D11zz10dddd01101QM0mmmm") // v8
INST(v8_VRINTP, "VRINTP", "111100111D11zz10dddd01111QM0mmmm") // v8
INST(asimd_VCVT_half, "VCVT (half-precision)", "111100111D11zz10dddd011o00M0mmmm") // ASIMD
INST(arm_UDF, "UNALLOCATED", "111100111-11--10----011-01-0----") // ASIMD
INST(v8_VCVTA, "VCVTA", "111100111D11zz11dddd0000oQM0mmmm") // v8
INST(v8_VCVTN, "VCVTN", "111100111D11zz11dddd0001oQM0mmmm") // v8
INST(v8_VCVTP, "VCVTP", "111100111D11zz11dddd0010oQM0mmmm") // v8
INST(v8_VCVTM, "VCVTM", "111100111D11zz11dddd0011oQM0mmmm") // v8
INST(asimd_VRECPE, "VRECPE", "111100111D11zz11dddd010F0QM0mmmm") // ASIMD
INST(asimd_VRSQRTE, "VRSQRTE", "111100111D11zz11dddd010F1QM0mmmm") // ASIMD
INST(asimd_VCVT_integer, "VCVT (integer)", "111100111D11zz11dddd011oUQM0mmmm") // ASIMD
// Two registers, cryptography
INST(v8_AESE, "AESE", "111100111D11zz00dddd001100M0mmmm") // v8
INST(v8_AESD, "AESD", "111100111D11zz00dddd001101M0mmmm") // v8
INST(v8_AESMC, "AESMC", "111100111D11zz00dddd001110M0mmmm") // v8
INST(v8_AESIMC, "AESIMC", "111100111D11zz00dddd001111M0mmmm") // v8
INST(arm_UDF, "UNALLOCATED", "111100111-11--01----001010-0----") // v8
INST(arm_UDF, "UNALLOCATED (SHA1H)", "111100111-11--01----001011-0----") // v8
INST(arm_UDF, "UNALLOCATED (SHA1SU1)", "111100111-11--10----001110-0----") // v8
INST(v8_SHA256SU0, "SHA256SU0", "111100111D11zz10dddd001111M0mmmm") // v8
// One register and modified immediate
INST(asimd_VMOV_imm, "VBIC, VMOV, VMVN, VORR (immediate)", "1111001a1D000bcdVVVVmmmm0Qo1efgh") // ASIMD
// Miscellaneous
INST(asimd_VEXT, "VEXT", "111100101D11nnnnddddiiiiNQM0mmmm") // ASIMD
INST(asimd_VTBL, "VTBL", "111100111D11nnnndddd10zzN0M0mmmm") // ASIMD
INST(asimd_VTBX, "VTBX", "111100111D11nnnndddd10zzN1M0mmmm") // ASIMD
INST(asimd_VDUP_scalar, "VDUP (scalar)", "111100111D11iiiidddd11000QM0mmmm") // ASIMD
INST(arm_UDF, "UNALLOCATED", "111100111-11--------11-----0----") // ASIMD
// Advanced SIMD load/store structures
INST(v8_VST_multiple, "VST{1-4} (multiple)", "111101000D00nnnnddddxxxxzzaammmm") // v8
INST(v8_VLD_multiple, "VLD{1-4} (multiple)", "111101000D10nnnnddddxxxxzzaammmm") // v8
INST(arm_UDF, "UNALLOCATED", "111101000--0--------1011--------") // v8
INST(arm_UDF, "UNALLOCATED", "111101000--0--------11----------") // v8
INST(arm_UDF, "UNALLOCATED", "111101001-00--------11----------") // v8
INST(v8_VLD_all_lanes, "VLD{1-4} (all lanes)", "111101001D10nnnndddd11nnzzTammmm") // v8
INST(v8_VST_single, "VST{1-4} (single)", "111101001D00nnnnddddzzNNaaaammmm") // v8
INST(v8_VLD_single, "VLD{1-4} (single)", "111101001D10nnnnddddzzNNaaaammmm") // v8
INST(asimd_VMOV_imm, "VBIC, VMOV, VMVN, VORR (immediate)", "1111001a1D000bcdVVVVmmmm0Qo1efgh")
INST(asimd_VEXT, "VEXT", "111100101D11nnnnddddiiiiNQM0mmmm")
INST(asimd_VTBL, "VTBL", "111100111D11nnnndddd10zzN0M0mmmm")
INST(asimd_VTBX, "VTBX", "111100111D11nnnndddd10zzN1M0mmmm")
INST(asimd_VDUP_scalar, "VDUP (scalar)", "111100111D11iiiidddd11000QM0mmmm")
INST(asimd_VSWP, "VSWP", "111100111D110010dddd00000QM0mmmm")
INST(asimd_VMOVN, "VMOVN", "111100111D11zz10dddd001000M0mmmm")
INST(asimd_VQMOVUN, "VQMOVUN", "111100111D11zz10dddd001001M0mmmm")
INST(asimd_VSHLL_max, "VSHLL_max", "111100111D11zz10dddd001100M0mmmm")
INST(v8_AESE, "AESE", "111100111D11zz00dddd001100M0mmmm")
INST(v8_AESD, "AESD", "111100111D11zz00dddd001101M0mmmm")
INST(v8_AESMC, "AESMC", "111100111D11zz00dddd001110M0mmmm")
INST(v8_AESIMC, "AESIMC", "111100111D11zz00dddd001111M0mmmm")
INST(arm_UDF, "UNALLOCATED", "111100111-11--01----001010-0----")
INST(arm_UDF, "UNALLOCATED (SHA1H)", "111100111-11--01----001011-0----")
INST(arm_UDF, "UNALLOCATED (SHA1SU1)", "111100111-11--10----001110-0----")
INST(v8_SHA256SU0, "SHA256SU0", "111100111D11zz10dddd001111M0mmmm")
INST(asimd_VCLS, "VCLS", "111100111D11zz00dddd01000QM0mmmm")
INST(asimd_VCLZ, "VCLZ", "111100111D11zz00dddd01001QM0mmmm")
INST(asimd_VCNT, "VCNT", "111100111D11zz00dddd01010QM0mmmm")
INST(asimd_VMVN_reg, "VMVN_reg", "111100111D11zz00dddd01011QM0mmmm")
INST(asimd_VQABS, "VQABS", "111100111D11zz00dddd01110QM0mmmm")
INST(asimd_VQNEG, "VQNEG", "111100111D11zz00dddd01111QM0mmmm")
INST(arm_UDF, "UNALLOCATED", "111100111-11--01----01101--0----")
INST(arm_UDF, "UNALLOCATED", "111100111-11--10----00000--0----")
INST(asimd_VTRN, "VTRN", "111100111D11zz10dddd00001QM0mmmm")
INST(asimd_VUZP, "VUZP", "111100111D11zz10dddd00010QM0mmmm")
INST(asimd_VZIP, "VZIP", "111100111D11zz10dddd00011QM0mmmm")
INST(asimd_VQMOVN, "VQMOVN", "111100111D11zz10dddd00101oM0mmmm")
INST(v8_VRINTN, "VRINTN", "111100111D11zz10dddd01000QM0mmmm")
INST(v8_VRINTX, "VRINTX", "111100111D11zz10dddd01001QM0mmmm")
INST(v8_VRINTA, "VRINTA", "111100111D11zz10dddd01010QM0mmmm")
INST(v8_VRINTZ, "VRINTZ", "111100111D11zz10dddd01011QM0mmmm")
INST(v8_VRINTM, "VRINTM", "111100111D11zz10dddd01101QM0mmmm")
INST(v8_VRINTP, "VRINTP", "111100111D11zz10dddd01111QM0mmmm")
INST(asimd_VCVT_half, "VCVT (half-precision)", "111100111D11zz10dddd011o00M0mmmm")
INST(arm_UDF, "UNALLOCATED", "111100111-11--10----011-01-0----")
INST(asimd_VPADDL, "VPADDL", "111100111D11zz00dddd0010oQM0mmmm")
INST(asimd_VPADAL, "VPADAL", "111100111D11zz00dddd0110oQM0mmmm")
INST(asimd_VCGT_zero, "VCGT (zero)", "111100111D11zz01dddd0F000QM0mmmm")
INST(asimd_VCGE_zero, "VCGE (zero)", "111100111D11zz01dddd0F001QM0mmmm")
INST(asimd_VCEQ_zero, "VCEQ (zero)", "111100111D11zz01dddd0F010QM0mmmm")
INST(asimd_VCLE_zero, "VCLE (zero)", "111100111D11zz01dddd0F011QM0mmmm")
INST(asimd_VCLT_zero, "VCLT (zero)", "111100111D11zz01dddd0F100QM0mmmm")
INST(asimd_VABS, "VABS", "111100111D11zz01dddd0F110QM0mmmm")
INST(asimd_VNEG, "VNEG", "111100111D11zz01dddd0F111QM0mmmm")
INST(v8_VCVTA, "VCVTA", "111100111D11zz11dddd0000oQM0mmmm")
INST(v8_VCVTN, "VCVTN", "111100111D11zz11dddd0001oQM0mmmm")
INST(v8_VCVTP, "VCVTP", "111100111D11zz11dddd0010oQM0mmmm")
INST(v8_VCVTM, "VCVTM", "111100111D11zz11dddd0011oQM0mmmm")
INST(asimd_VRECPE, "VRECPE", "111100111D11zz11dddd010F0QM0mmmm")
INST(asimd_VRSQRTE, "VRSQRTE", "111100111D11zz11dddd010F1QM0mmmm")
INST(asimd_VREV, "VREV{16,32,64}", "111100111D11zz00dddd000ooQM0mmmm")
INST(asimd_VCVT_integer, "VCVT (integer)", "111100111D11zz11dddd011oUQM0mmmm")
INST(asimd_VAND_reg, "VAND (register)", "111100100D00nnnndddd0001NQM1mmmm")
INST(asimd_VBIC_reg, "VBIC (register)", "111100100D01nnnndddd0001NQM1mmmm")
INST(asimd_VORR_reg, "VORR (register)", "111100100D10nnnndddd0001NQM1mmmm")
INST(asimd_VORN_reg, "VORN (register)", "111100100D11nnnndddd0001NQM1mmmm")
INST(asimd_VEOR_reg, "VEOR (register)", "111100110D00nnnndddd0001NQM1mmmm")
INST(asimd_VBSL, "VBSL", "111100110D01nnnndddd0001NQM1mmmm")
INST(asimd_VBIT, "VBIT", "111100110D10nnnndddd0001NQM1mmmm")
INST(asimd_VBIF, "VBIF", "111100110D11nnnndddd0001NQM1mmmm")
INST(v8_SHA256H, "SHA256H", "111100110D00nnnndddd1100NQM0mmmm")
INST(v8_SHA256H2, "SHA256H2", "111100110D01nnnndddd1100NQM0mmmm")
INST(v8_SHA256SU1, "SHA256SU1", "111100110D10nnnndddd1100NQM0mmmm")
INST(asimd_VSHRN, "VSHRN", "111100101Diiiiiidddd100000M1mmmm")
INST(asimd_VRSHRN, "VRSHRN", "111100101Diiiiiidddd100001M1mmmm")
INST(asimd_VQSHRUN, "VQSHRUN", "111100111Diiiiiidddd100000M1mmmm")
INST(asimd_VQRSHRUN, "VQRSHRUN", "111100111Diiiiiidddd100001M1mmmm")
INST(v8_VMAXNM, "VMAXNM", "111100110D0znnnndddd1111NQM1mmmm")
INST(v8_VMINNM, "VMINNM", "111100110D1znnnndddd1111NQM1mmmm")
INST(asimd_VFMA, "VFMA", "111100100D0znnnndddd1100NQM1mmmm")
INST(asimd_VFMS, "VFMS", "111100100D1znnnndddd1100NQM1mmmm")
INST(asimd_VADD_float, "VADD (floating-point)", "111100100D0znnnndddd1101NQM0mmmm")
INST(asimd_VSUB_float, "VSUB (floating-point)", "111100100D1znnnndddd1101NQM0mmmm")
INST(asimd_VPADD_float, "VPADD (floating-point)", "111100110D0znnnndddd1101NQM0mmmm")
INST(asimd_VABD_float, "VABD (floating-point)", "111100110D1znnnndddd1101NQM0mmmm")
INST(asimd_VMLA_float, "VMLA (floating-point)", "111100100D0znnnndddd1101NQM1mmmm")
INST(asimd_VMLS_float, "VMLS (floating-point)", "111100100D1znnnndddd1101NQM1mmmm")
INST(asimd_VMUL_float, "VMUL (floating-point)", "111100110D0znnnndddd1101NQM1mmmm")
INST(asimd_VCEQ_reg_float, "VCEQ (register)", "111100100D0znnnndddd1110NQM0mmmm")
INST(asimd_VCGE_reg_float, "VCGE (register)", "111100110D0znnnndddd1110NQM0mmmm")
INST(asimd_VCGT_reg_float, "VCGT (register)", "111100110D1znnnndddd1110NQM0mmmm")
INST(asimd_VMAX_float, "VMAX (floating-point)", "111100100D0znnnndddd1111NQM0mmmm")
INST(asimd_VMIN_float, "VMIN (floating-point)", "111100100D1znnnndddd1111NQM0mmmm")
INST(asimd_VPMAX_float, "VPMAX (floating-point)", "111100110D0znnnndddd1111NQM0mmmm")
INST(asimd_VPMIN_float, "VPMIN (floating-point)", "111100110D1znnnndddd1111NQM0mmmm")
INST(asimd_VRECPS, "VRECPS", "111100100D0znnnndddd1111NQM1mmmm")
INST(asimd_VRSQRTS, "VRSQRTS", "111100100D1znnnndddd1111NQM1mmmm")
INST(asimd_VQSHRN, "VQSHRN", "1111001U1Diiiiiidddd100100M1mmmm")
INST(asimd_VQRSHRN, "VQRSHRN", "1111001U1Diiiiiidddd100101M1mmmm")
INST(asimd_VSHLL, "VSHLL", "1111001U1Diiiiiidddd101000M1mmmm")
INST(asimd_VADD_int, "VADD (integer)", "111100100Dzznnnndddd1000NQM0mmmm")
INST(asimd_VSUB_int, "VSUB (integer)", "111100110Dzznnnndddd1000NQM0mmmm")
INST(asimd_VTST, "VTST", "111100100Dzznnnndddd1000NQM1mmmm")
INST(asimd_VCEQ_reg, "VCEG (register)", "111100110Dzznnnndddd1000NQM1mmmm")
INST(asimd_VQDMULH, "VQDMULH", "111100100Dzznnnndddd1011NQM0mmmm")
INST(asimd_VQRDMULH, "VQRDMULH", "111100110Dzznnnndddd1011NQM0mmmm")
INST(asimd_VPADD, "VPADD", "111100100Dzznnnndddd1011NQM1mmmm")
INST(asimd_VACGE, "VACGE", "111100110Doznnnndddd1110NQM1mmmm")
INST(asimd_VABAL, "VABAL", "1111001U1Dzznnnndddd0101N0M0mmmm")
INST(asimd_VABDL, "VABDL", "1111001U1Dzznnnndddd0111N0M0mmmm")
INST(asimd_VSRI, "VSRI", "111100111Diiiiiidddd0100LQM1mmmm")
INST(asimd_VSHL, "VSHL", "111100101Diiiiiidddd0101LQM1mmmm")
INST(asimd_VSLI, "VSLI", "111100111Diiiiiidddd0101LQM1mmmm")
INST(arm_UDF, "UNALLOCATED", "111100111-11--------11-----0----")
INST(arm_UDF, "UNALLOCATED", "111101000--0--------1011--------")
INST(asimd_VHADD, "VHADD", "1111001U0Dzznnnndddd0000NQM0mmmm")
INST(asimd_VQADD, "VQADD", "1111001U0Dzznnnndddd0000NQM1mmmm")
INST(asimd_VRHADD, "VRHADD", "1111001U0Dzznnnndddd0001NQM0mmmm")
INST(asimd_VHSUB, "VHSUB", "1111001U0Dzznnnndddd0010NQM0mmmm")
INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd0010NQM1mmmm")
INST(asimd_VCGT_reg, "VCGT (register)", "1111001U0Dzznnnndddd0011NQM0mmmm")
INST(asimd_VCGE_reg, "VCGE (register)", "1111001U0Dzznnnndddd0011NQM1mmmm")
INST(asimd_VSHL_reg, "VSHL (register)", "1111001U0Dzznnnndddd0100NQM0mmmm")
INST(asimd_VQSHL_reg, "VQSHL (register)", "1111001U0Dzznnnndddd0100NQM1mmmm")
INST(asimd_VRSHL, "VRSHL", "1111001U0Dzznnnndddd0101NQM0mmmm")
INST(asimd_VABD, "VABD", "1111001U0Dzznnnndddd0111NQM0mmmm")
INST(asimd_VABA, "VABA", "1111001U0Dzznnnndddd0111NQM1mmmm")
INST(asimd_VMLA, "VMLA/VMLS", "1111001o0Dzznnnndddd1001NQM0mmmm")
INST(asimd_VMUL, "VMUL", "1111001P0Dzznnnndddd1001NQM1mmmm")
INST(asimd_VADDL, "VADDL/VADDW", "1111001U1Dzznnnndddd000oN0M0mmmm")
INST(asimd_VSUBL, "VSUBL/VSUBW", "1111001U1Dzznnnndddd001oN0M0mmmm")
INST(asimd_VMLAL, "VMLAL/VMLSL", "1111001U1Dzznnnndddd10o0N0M0mmmm")
INST(asimd_VMULL, "VMULL", "1111001U1Dzznnnndddd11P0N0M0mmmm")
INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm")
INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm")
INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm")
INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm")
INST(asimd_VCVT_fixed, "VCVT (fixed-point)", "1111001U1Diiiiiidddd111o0QM1mmmm")
INST(arm_UDF, "UNALLOCATED", "111101001-00--------11----------")
INST(v8_VLD_all_lanes, "VLD{1-4} (all lanes)", "111101001D10nnnndddd11nnzzTammmm")
INST(asimd_VMAX, "VMAX/VMIN (integer)", "1111001U0Dzznnnnmmmm0110NQMommmm")
INST(asimd_VPMAX_int, "VPMAX/VPMIN (integer)", "1111001U0Dzznnnndddd1010NQMommmm")
INST(asimd_VQSHL, "VQSHL", "1111001U1Diiiiiidddd011oLQM1mmmm")
INST(arm_UDF, "UNALLOCATED", "111101000--0--------11----------")
INST(v8_VST_multiple, "VST{1-4} (multiple)", "111101000D00nnnnddddxxxxzzaammmm")
INST(v8_VLD_multiple, "VLD{1-4} (multiple)", "111101000D10nnnnddddxxxxzzaammmm")
INST(v8_VST_single, "VST{1-4} (single)", "111101001D00nnnnddddzzNNaaaammmm")
INST(v8_VLD_single, "VLD{1-4} (single)", "111101001D10nnnnddddzzNNaaaammmm")
INST(asimd_VMLA_scalar, "VMLA (scalar)", "1111001Q1Dzznnnndddd0o0FN1M0mmmm")
INST(asimd_VMLAL_scalar, "VMLAL (scalar)", "1111001U1dzznnnndddd0o10N1M0mmmm")
INST(asimd_VMUL_scalar, "VMUL (scalar)", "1111001Q1Dzznnnndddd100FN1M0mmmm")
INST(asimd_VMULL_scalar, "VMULL (scalar)", "1111001U1Dzznnnndddd1010N1M0mmmm")
INST(asimd_VQDMULL_scalar, "VQDMULL (scalar)", "111100101Dzznnnndddd1011N1M0mmmm")
INST(asimd_VQDMULH_scalar, "VQDMULH (scalar)", "1111001Q1Dzznnnndddd1100N1M0mmmm")
INST(asimd_VQRDMULH_scalar, "VQRDMULH (scalar)", "1111001Q1Dzznnnndddd1101N1M0mmmm")

View file

@ -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
/* This file is part of the dynarmic project.
@ -24,8 +24,8 @@ template<typename Visitor>
using Thumb16Matcher = Decoder::Matcher<Visitor, u16>;
template<typename V>
std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
alignas(64) static const std::vector<Thumb16Matcher<V>> table = {
static std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
alignas(64) static const auto table = std::array{
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)),
#include "./thumb16.inc"
#undef INST
@ -37,7 +37,7 @@ std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16
}
template<typename V>
std::optional<std::string_view> GetNameThumb16(u32 inst) noexcept {
static std::optional<std::string_view> GetNameThumb16(u32 inst) noexcept {
std::vector<std::pair<std::string_view, Thumb16Matcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)) },
#include "./thumb16.inc"

View file

@ -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
/* This file is part of the dynarmic project.
@ -23,8 +23,8 @@ template<typename Visitor>
using Thumb32Matcher = Decoder::Matcher<Visitor, u32>;
template<typename V>
std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32 instruction) {
alignas(64) static const std::vector<Thumb32Matcher<V>> table = {
static std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32 instruction) {
alignas(64) static const auto table = std::array{
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./thumb32.inc"
#undef INST
@ -36,7 +36,7 @@ std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32
}
template<typename V>
std::optional<std::string_view> GetNameThumb32(u32 inst) noexcept {
static std::optional<std::string_view> GetNameThumb32(u32 inst) noexcept {
std::vector<std::pair<std::string_view, Thumb32Matcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./thumb32.inc"

View file

@ -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
/* This file is part of the dynarmic project.
@ -24,7 +24,7 @@ template<typename Visitor>
using VFPMatcher = Decoder::Matcher<Visitor, u32>;
template<typename V>
std::optional<std::reference_wrapper<const VFPMatcher<V>>> DecodeVFP(u32 instruction) {
static std::optional<std::reference_wrapper<const VFPMatcher<V>>> DecodeVFP(u32 instruction) {
using Table = std::vector<VFPMatcher<V>>;
alignas(64) static const struct Tables {
Table unconditional;
@ -52,7 +52,7 @@ std::optional<std::reference_wrapper<const VFPMatcher<V>>> DecodeVFP(u32 instruc
}
template<typename V>
std::optional<std::string_view> GetNameVFP(u32 inst) noexcept {
static std::optional<std::string_view> GetNameVFP(u32 inst) noexcept {
std::vector<std::pair<std::string_view, VFPMatcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./vfp.inc"

View file

@ -36,33 +36,19 @@ inline size_t ToFastLookupIndex(u32 instruction) {
} // namespace detail
template<typename V>
constexpr DecodeTable<V> GetDecodeTable() {
std::vector<std::pair<const char*, Matcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./a64.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& a, const auto& b) {
// If a matcher has more bits in its mask it is more specific, so it should come first.
return mcl::bit::count_ones(a.second.GetMask()) > mcl::bit::count_ones(b.second.GetMask());
});
// Exceptions to the above rule of thumb.
std::stable_partition(list.begin(), list.end(), [&](const auto& e) {
return std::set<std::string>{
"MOVI, MVNI, ORR, BIC (vector, immediate)",
"FMOV (vector, immediate)",
"Unallocated SIMD modified immediate",
}.count(e.first) > 0;
});
inline DecodeTable<V> GetDecodeTable() {
DecodeTable<V> table{};
for (size_t i = 0; i < table.size(); ++i) {
for (auto const& e : list) {
const auto expect = detail::ToFastLookupIndex(e.second.GetExpected());
const auto mask = detail::ToFastLookupIndex(e.second.GetMask());
if ((i & mask) == expect) {
table[i].push_back(e.second);
}
// PLEASE HEAP ELLIDE
for (auto const& e : std::vector<Matcher<V>>{
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./a64.inc"
#undef INST
}) {
const auto expect = detail::ToFastLookupIndex(e.GetExpected());
const auto mask = detail::ToFastLookupIndex(e.GetMask());
if ((i & mask) == expect)
table[i].push_back(e);
}
}
return table;
@ -70,7 +56,7 @@ constexpr DecodeTable<V> GetDecodeTable() {
/// In practice it must always suceed, otherwise something else unrelated would have gone awry
template<typename V>
std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) {
inline std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) {
alignas(64) static const auto table = GetDecodeTable<V>();
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) {
@ -82,7 +68,7 @@ std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction)
}
template<typename V>
std::optional<std::string_view> GetName(u32 inst) noexcept {
inline std::optional<std::string_view> GetName(u32 inst) noexcept {
std::vector<std::pair<std::string_view, Matcher<V>>> list = {
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
#include "./a64.inc"

File diff suppressed because it is too large Load diff

View file

@ -109,12 +109,12 @@ public:
return static_cast<u32>(other_cpu_addr - cpu_addr);
}
size_t getLRUID() const noexcept {
return lru_id;
u64 GetFrameTick() const noexcept {
return frame_tick;
}
void setLRUID(size_t lru_id_) {
lru_id = lru_id_;
void SetFrameTick(u64 tick) noexcept {
frame_tick = tick;
}
size_t SizeBytes() const {
@ -125,7 +125,7 @@ private:
VAddr cpu_addr = 0;
BufferFlagBits flags{};
int stream_score = 0;
size_t lru_id = SIZE_MAX;
u64 frame_tick = 0;
size_t size_bytes = 0;
};

View file

@ -58,17 +58,22 @@ void BufferCache<P>::RunGarbageCollector() {
const bool aggressive_gc = total_used_memory >= critical_memory;
const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
int num_iterations = aggressive_gc ? 64 : 32;
const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
const u64 threshold = frame_tick - ticks_to_destroy;
boost::container::small_vector<BufferId, 64> expired;
for (auto [id, buffer] : slot_buffers) {
if (buffer->GetFrameTick() < threshold) {
expired.push_back(id);
}
}
for (const auto buffer_id : expired) {
if (num_iterations == 0) {
return true;
break;
}
--num_iterations;
auto& buffer = slot_buffers[buffer_id];
DownloadBufferMemory(buffer);
DeleteBuffer(buffer_id);
return false;
};
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
}
}
template <class P>
@ -1595,10 +1600,9 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
const auto size = buffer.SizeBytes();
if (insert) {
total_used_memory += Common::AlignUp(size, 1024);
buffer.setLRUID(lru_cache.Insert(buffer_id, frame_tick));
buffer.SetFrameTick(frame_tick);
} else {
total_used_memory -= Common::AlignUp(size, 1024);
lru_cache.Free(buffer.getLRUID());
}
const DAddr device_addr_begin = buffer.CpuAddr();
const DAddr device_addr_end = device_addr_begin + size;
@ -1616,7 +1620,7 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
template <class P>
void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
if (buffer_id != NULL_BUFFER_ID) {
lru_cache.Touch(buffer.getLRUID(), frame_tick);
buffer.SetFrameTick(frame_tick);
}
}

View file

@ -23,7 +23,6 @@
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/literals.h"
#include "common/lru_cache.h"
#include "common/range_sets.h"
#include "common/scope_exit.h"
#include "common/settings.h"
@ -506,11 +505,6 @@ private:
size_t immediate_buffer_capacity = 0;
Common::ScratchBuffer<u8> immediate_buffer_alloc;
struct LRUItemParams {
using ObjectType = BufferId;
using TickType = u64;
};
Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
u64 frame_tick = 0;
u64 total_used_memory = 0;
u64 minimum_memory = 0;

View file

@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@ -122,7 +122,35 @@ void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands) {
dma_state.is_last_call = true;
index += max_write;
} else if (dma_state.method_count) {
auto const command_header = commands[index]; //can copy
if (!dma_state.non_incrementing && !dma_increment_once &&
dma_state.method >= non_puller_methods) {
auto subchannel = subchannels[dma_state.subchannel];
const u32 available = u32(std::min<size_t>(
index + dma_state.method_count, commands.size()) - index);
u32 batch = 0;
u32 method = dma_state.method;
while (batch < available) {
const bool needs_exec =
(method < Engines::EngineInterface::EXECUTION_MASK_TABLE_SIZE)
? subchannel->execution_mask[method]
: subchannel->execution_mask_default;
if (needs_exec) break;
batch++;
method++;
}
if (batch > 0) {
auto& sink = subchannel->method_sink;
sink.reserve(sink.size() + batch);
for (u32 j = 0; j < batch; j++) {
sink.emplace_back(dma_state.method + j, commands[index + j].argument);
}
dma_state.method += batch;
dma_state.method_count -= batch;
index += batch;
continue;
}
}
auto const command_header = commands[index];
dma_state.dma_word_offset = u32(index * sizeof(u32));
dma_state.is_last_call = dma_state.method_count <= 1;
CallMethod(command_header.argument);
@ -181,7 +209,11 @@ void DmaPusher::CallMethod(u32 argument) const {
});
} else {
auto subchannel = subchannels[dma_state.subchannel];
if (!subchannel->execution_mask[dma_state.method]) {
const bool needs_execution =
(dma_state.method < Engines::EngineInterface::EXECUTION_MASK_TABLE_SIZE)
? subchannel->execution_mask[dma_state.method]
: subchannel->execution_mask_default;
if (!needs_execution) {
subchannel->method_sink.emplace_back(dma_state.method, argument);
} else {
subchannel->ConsumeSink();

View file

@ -6,9 +6,9 @@
#pragma once
#include <bitset>
#include <limits>
#include <vector>
#include <array>
#include <boost/container/small_vector.hpp>
#include "common/common_types.h"
@ -41,8 +41,11 @@ public:
ConsumeSinkImpl();
}
std::bitset<(std::numeric_limits<u16>::max)()> execution_mask{};
std::vector<std::pair<u32, u32>> method_sink{};
static constexpr size_t EXECUTION_MASK_TABLE_SIZE = 0xE00;
std::array<u8, EXECUTION_MASK_TABLE_SIZE> execution_mask{};
bool execution_mask_default{};
boost::container::small_vector<std::pair<u32, u32>, 64> method_sink{};
bool current_dirty{};
GPUVAddr current_dma_segment;

View file

@ -26,7 +26,7 @@ Fermi2D::Fermi2D(MemoryManager& memory_manager_) : memory_manager{memory_manager
regs.src.depth = 1;
regs.dst.depth = 1;
execution_mask.reset();
execution_mask.fill(0);
execution_mask[FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1] = true;
}

View file

@ -18,7 +18,7 @@ namespace Tegra::Engines {
KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
: system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {
execution_mask.reset();
execution_mask.fill(0);
execution_mask[KEPLER_COMPUTE_REG_INDEX(exec_upload)] = true;
execution_mask[KEPLER_COMPUTE_REG_INDEX(data_upload)] = true;
execution_mask[KEPLER_COMPUTE_REG_INDEX(launch)] = true;

View file

@ -22,7 +22,7 @@ KeplerMemory::~KeplerMemory() = default;
void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
upload_state.BindRasterizer(rasterizer_);
execution_mask.reset();
execution_mask.fill(0);
execution_mask[KEPLERMEMORY_REG_INDEX(exec)] = true;
execution_mask[KEPLERMEMORY_REG_INDEX(data)] = true;
}

View file

@ -4,8 +4,10 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <cstring>
#include <optional>
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/scope_exit.h"
@ -37,9 +39,10 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
{
dirty.flags.flip();
InitializeRegisterDefaults();
execution_mask.reset();
for (size_t i = 0; i < execution_mask.size(); i++)
execution_mask.fill(0);
for (size_t i = 0; i < EXECUTION_MASK_TABLE_SIZE; i++)
execution_mask[i] = IsMethodExecutable(u32(i));
execution_mask_default = true;
}
Maxwell3D::~Maxwell3D() = default;
@ -298,18 +301,27 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
}
void Maxwell3D::ConsumeSinkImpl() {
std::stable_sort(method_sink.begin(), method_sink.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
const auto sink_size = method_sink.size();
const auto control = shadow_state.shadow_ram_control;
if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) {
for (auto [method, value] : method_sink) {
for (size_t i = 0; i < sink_size; ++i) {
const auto [method, value] = method_sink[i];
shadow_state.reg_array[method] = value;
ProcessDirtyRegisters(method, value);
}
} else if (control == Regs::ShadowRamControl::Replay) {
for (auto [method, value] : method_sink)
for (size_t i = 0; i < sink_size; ++i) {
const auto [method, value] = method_sink[i];
ProcessDirtyRegisters(method, shadow_state.reg_array[method]);
}
} else {
for (auto [method, value] : method_sink)
for (size_t i = 0; i < sink_size; ++i) {
const auto [method, value] = method_sink[i];
ProcessDirtyRegisters(method, value);
}
}
method_sink.clear();
}

View file

@ -23,7 +23,7 @@ using namespace Texture;
MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
: system{system_}, memory_manager{memory_manager_} {
execution_mask.reset();
execution_mask.fill(0);
execution_mask[offsetof(Regs, launch_dma) / sizeof(u32)] = true;
}

View file

@ -118,8 +118,6 @@ if (NOT GLSLANG_ERROR STREQUAL "")
set(QUIET_FLAG "")
endif()
# Shader files must depend on their directory otherwise *BSD make will spontaneously combust
file(MAKE_DIRECTORY "${SHADER_DIR}")
foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES})
get_filename_component(FILENAME ${SOURCE_FILE} NAME)
string(REPLACE "." "_" SHADER_NAME ${FILENAME})
@ -135,7 +133,6 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES})
${SOURCE_FILE}
DEPENDS
${INPUT_FILE}
${SHADER_DIR}
# HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified
)
set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE})
@ -151,8 +148,6 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES})
${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} --target-env ${SPIR_V_VERSION}
MAIN_DEPENDENCY
${SOURCE_FILE}
DEPENDS
${SHADER_DIR}
)
set(SHADER_HEADERS ${SHADER_HEADERS} ${SPIRV_HEADER_FILE})
endif()
@ -172,7 +167,6 @@ foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
${SOURCE_FILE}
DEPENDS
${INPUT_FILE}
${SHADER_DIR}
# HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified
)
set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE})

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -102,7 +105,7 @@ struct ImageBase {
VAddr cpu_addr_end = 0;
u64 modification_tick = 0;
size_t lru_index = SIZE_MAX;
u64 last_use_tick = 0;
std::array<u32, MAX_MIP_LEVELS> mip_level_offsets{};

View file

@ -6,6 +6,7 @@
#pragma once
#include <algorithm>
#include <limits>
#include <optional>
#include <bit>
@ -118,24 +119,17 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
template <class P>
void TextureCache<P>::RunGarbageCollector() {
bool high_priority_mode = false;
bool high_priority_mode = total_used_memory >= expected_memory;
bool aggressive_mode = false;
u64 ticks_to_destroy = 0;
size_t num_iterations = 0;
const auto Configure = [&](bool allow_aggressive) {
high_priority_mode = total_used_memory >= expected_memory;
aggressive_mode = allow_aggressive && total_used_memory >= critical_memory;
ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
};
u64 ticks_to_destroy = high_priority_mode ? 25ULL : 50ULL;
size_t num_iterations = high_priority_mode ? 20 : 10;
const auto Cleanup = [this, &num_iterations, &high_priority_mode,
&aggressive_mode](ImageId image_id) {
if (num_iterations == 0) {
return true;
}
--num_iterations;
auto& image = slot_images[image_id];
// Never delete recently allocated sparse textures (within 3 frames)
@ -145,12 +139,9 @@ void TextureCache<P>::RunGarbageCollector() {
}
if (True(image.flags & ImageFlagBits::IsDecoding)) {
// This image is still being decoded, deleting it will invalidate the slot
// used by the async decoder thread.
return false;
}
// Prioritize large sparse textures for cleanup
const bool is_large_sparse = lowmemorydevice &&
image.info.is_sparse &&
image.guest_size_bytes >= 256_MiB;
@ -166,6 +157,8 @@ void TextureCache<P>::RunGarbageCollector() {
return false;
}
--num_iterations;
if (must_download && !is_large_sparse) {
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
@ -183,7 +176,6 @@ void TextureCache<P>::RunGarbageCollector() {
if (total_used_memory < critical_memory) {
if (aggressive_mode) {
// Sink the aggresiveness.
num_iterations >>= 2;
aggressive_mode = false;
return false;
@ -196,31 +188,64 @@ void TextureCache<P>::RunGarbageCollector() {
return false;
};
// Aggressively clear massive sparse textures
if (total_used_memory >= expected_memory) {
lru_cache.ForEachItemBelow(frame_tick, [&](ImageId image_id) {
auto& image = slot_images[image_id];
// Only target sparse textures that are old enough
if (lowmemorydevice &&
image.info.is_sparse &&
image.guest_size_bytes >= 256_MiB &&
image.allocation_tick < frame_tick - 3) {
LOG_DEBUG(HW_GPU, "GC targeting old sparse texture at 0x{:X} ({} MiB, age: {} frames)",
image.gpu_addr, image.guest_size_bytes / (1024 * 1024),
frame_tick - image.allocation_tick);
return Cleanup(image_id);
}
return false;
const auto SortByAge = [this](auto& vec) {
std::sort(vec.begin(), vec.end(), [this](ImageId a, ImageId b) {
return slot_images[a].last_use_tick < slot_images[b].last_use_tick;
});
};
// Single pass: collect all candidates, classified by tier
const u64 normal_threshold = frame_tick > ticks_to_destroy ? frame_tick - ticks_to_destroy : 0;
const u64 aggressive_threshold = frame_tick > 10 ? frame_tick - 10 : 0;
boost::container::small_vector<ImageId, 64> sparse_candidates;
boost::container::small_vector<ImageId, 64> expired;
boost::container::small_vector<ImageId, 64> aggressive_expired;
for (auto [id, image] : slot_images) {
if (False(image->flags & ImageFlagBits::Registered)) {
continue;
}
const u64 tick = image->last_use_tick;
if (tick < normal_threshold) {
expired.push_back(id);
} else if (tick < aggressive_threshold) {
aggressive_expired.push_back(id);
} else if (high_priority_mode && tick < frame_tick &&
lowmemorydevice && image->info.is_sparse &&
image->guest_size_bytes >= 256_MiB) {
sparse_candidates.push_back(id);
}
}
Configure(false);
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
SortByAge(expired);
SortByAge(aggressive_expired);
// If pressure is still too high, prune aggressively.
// Tier 1: large sparse textures under memory pressure
for (const auto image_id : sparse_candidates) {
auto& image = slot_images[image_id];
if (image.allocation_tick < frame_tick - 3) {
if (Cleanup(image_id)) {
break;
}
}
}
// Tier 2: normal expiration
for (const auto image_id : expired) {
if (Cleanup(image_id)) {
break;
}
}
// Tier 3: if still critical, use aggressive threshold with more iterations
if (total_used_memory >= critical_memory) {
Configure(true);
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
aggressive_mode = true;
num_iterations = 40;
for (const auto image_id : aggressive_expired) {
if (Cleanup(image_id)) {
break;
}
}
}
}
@ -2027,8 +2052,8 @@ std::pair<u32, u32> TextureCache<P>::PrepareDmaImage(ImageId dst_id, GPUVAddr ba
const auto& image = slot_images[dst_id];
const auto base = image.TryFindBase(base_addr);
PrepareImage(dst_id, mark_as_modified, false);
const auto& new_image = slot_images[dst_id];
lru_cache.Touch(new_image.lru_index, frame_tick);
auto& new_image = slot_images[dst_id];
new_image.last_use_tick = frame_tick;
return std::make_pair(base->level, base->layer);
}
@ -2377,7 +2402,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory += Common::AlignUp(tentative_size, 1024);
image.lru_index = lru_cache.Insert(image_id, frame_tick);
image.last_use_tick = frame_tick;
ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, image_id](u64 page) {
(*channel_state->gpu_page_table)[page].push_back(image_id);
@ -2411,7 +2436,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
"Trying to unregister an already registered image");
image.flags &= ~ImageFlagBits::Registered;
image.flags &= ~ImageFlagBits::BadOverlap;
lru_cache.Free(image.lru_index);
const auto& clear_page_table =
[image_id](u64 page, ankerl::unordered_dense::map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& selected_page_table) {
const auto page_it = selected_page_table.find(page);
@ -2733,12 +2758,14 @@ void TextureCache<P>::PrepareImage(ImageId image_id, bool is_modification, bool
}
} else {
RefreshContents(image, image_id);
SynchronizeAliases(image_id);
if (!image.aliased_images.empty()) {
SynchronizeAliases(image_id);
}
}
if (is_modification) {
MarkModification(image);
}
lru_cache.Touch(image.lru_index, frame_tick);
image.last_use_tick = frame_tick;
}
template <class P>

View file

@ -22,7 +22,7 @@
#include "common/common_types.h"
#include "common/hash.h"
#include "common/literals.h"
#include "common/lru_cache.h"
#include <ranges>
#include "common/scratch_buffer.h"
#include "common/slot_vector.h"
@ -510,11 +510,7 @@ private:
std::deque<std::vector<AsyncBuffer>> async_buffers;
std::deque<AsyncBuffer> async_buffers_death_ring;
struct LRUItemParams {
using ObjectType = ImageId;
using TickType = u64;
};
Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
#ifdef YUZU_LEGACY
static constexpr size_t TICKS_TO_DESTROY = 6;

1646
tools/gendynarm.cpp Normal file

File diff suppressed because it is too large Load diff