mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-15 05:15:14 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bccdabf99 | |||
| ac99ea96da | |||
| d1b7824443 | |||
| 34fa39eae8 | |||
| 9ace6742d7 | |||
| 79f29abcba | |||
| 3ce5463d2d | |||
| cae70c30fa | |||
| bcceced96d | |||
| 82e374f66c | |||
| 6e76014824 | |||
| bb71ace365 | |||
| 21f9db1c27 | |||
| b4a485e244 | |||
| 81a344f3db | |||
| c0fbb2526d | |||
| c3afd2fabd | |||
| ee2891c55e | |||
| dd91b41a78 | |||
| e9f4541069 | |||
| cf7086de7c | |||
| 8e14f07a69 | |||
| 0b179517b3 | |||
| 7a8176f63f |
@@ -3,8 +3,7 @@ name: tx-pull
|
||||
on:
|
||||
# monday, wednesday, saturday at 2pm
|
||||
schedule:
|
||||
cron:
|
||||
- '0 14 * * 1,3,6'
|
||||
cron: '0 14 * * 1,3,6'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -59,4 +58,3 @@ jobs:
|
||||
-H 'Authorization: Bearer ${{ secrets.CI_FJ_TOKEN }}' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "@data.json" --fail
|
||||
|
||||
@@ -37,10 +37,10 @@ set(GIT_DESC ${BUILD_VERSION})
|
||||
|
||||
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
|
||||
if (NIGHTLY_BUILD)
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
|
||||
set(BUILD_AUTO_UPDATE_API "api.github.com")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/repos/")
|
||||
set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly")
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
|
||||
set(BUILD_AUTO_UPDATE_REPO "eden-ci/nightly")
|
||||
set(REPO_NAME "Eden Nightly")
|
||||
else()
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
|
||||
|
||||
+89
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 19 KiB |
+1
@@ -0,0 +1 @@
|
||||
#43fcfcff
|
||||
+1
-1
@@ -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).
|
||||
|
||||
+35
-15
@@ -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
|
||||
```
|
||||
|
||||
@@ -25,6 +25,11 @@ import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.navigation.NavOptions
|
||||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||
import org.yuzu.yuzu_emu.utils.CustomSettingsHandler
|
||||
import android.util.Rational
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
@@ -87,6 +92,28 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
private val emulationViewModel: EmulationViewModel by viewModels()
|
||||
|
||||
private var foregroundService: Intent? = null
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
private var pendingRomSwapIntent: Intent? = null
|
||||
private var isWaitingForRomSwapStop = false
|
||||
private var romSwapNativeStopped = false
|
||||
private var romSwapThreadStopped = false
|
||||
private var romSwapGeneration = 0
|
||||
private var hasEmulationSession = processHasEmulationSession
|
||||
private val romSwapStopTimeoutRunnable = Runnable { onRomSwapStopTimeout() }
|
||||
|
||||
private fun onRomSwapStopTimeout() {
|
||||
if (!isWaitingForRomSwapStop) {
|
||||
return
|
||||
}
|
||||
Log.warning("[EmulationActivity] ROM swap stop timed out; retrying native stop and continuing to wait")
|
||||
NativeLibrary.stopEmulation()
|
||||
scheduleRomSwapStopTimeout()
|
||||
}
|
||||
|
||||
private fun scheduleRomSwapStopTimeout() {
|
||||
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
|
||||
mainHandler.postDelayed(romSwapStopTimeoutRunnable, ROM_SWAP_STOP_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
@@ -128,9 +155,29 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
binding = ActivityEmulationBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val launchIntent = Intent(intent)
|
||||
val shouldDeferLaunchForSwap = hasEmulationSession && isSwapIntent(launchIntent)
|
||||
if (shouldDeferLaunchForSwap) {
|
||||
Log.info("[EmulationActivity] onCreate detected existing session; deferring new game setup for swap")
|
||||
emulationViewModel.setIsEmulationStopping(true)
|
||||
emulationViewModel.setEmulationStopped(false)
|
||||
}
|
||||
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
|
||||
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras)
|
||||
val initialArgs = if (shouldDeferLaunchForSwap) {
|
||||
Bundle(intent.extras ?: Bundle()).apply {
|
||||
processSessionGame?.let { putParcelable("game", it) }
|
||||
}
|
||||
} else {
|
||||
intent.extras
|
||||
}
|
||||
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, initialArgs)
|
||||
if (shouldDeferLaunchForSwap) {
|
||||
mainHandler.post {
|
||||
handleSwapIntent(launchIntent)
|
||||
}
|
||||
}
|
||||
|
||||
isActivityRecreated = savedInstanceState != null
|
||||
|
||||
@@ -210,6 +257,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
|
||||
super.onDestroy()
|
||||
inputManager.unregisterInputDeviceListener(this)
|
||||
stopForegroundService(this)
|
||||
@@ -228,17 +276,123 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
|
||||
// Reset navigation graph with new intent data to recreate EmulationFragment
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
|
||||
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras)
|
||||
|
||||
handleSwapIntent(intent)
|
||||
nfcReader.onNewIntent(intent)
|
||||
InputHandler.updateControllerData()
|
||||
}
|
||||
|
||||
private fun isSwapIntent(intent: Intent): Boolean {
|
||||
return when {
|
||||
intent.getBooleanExtra(EXTRA_OVERLAY_GAMELESS_EDIT_MODE, false) -> false
|
||||
intent.action == CustomSettingsHandler.CUSTOM_CONFIG_ACTION -> true
|
||||
intent.data != null -> true
|
||||
else -> {
|
||||
val extras = intent.extras
|
||||
extras != null &&
|
||||
BundleCompat.getParcelable(extras, EXTRA_SELECTED_GAME, Game::class.java) != null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSwapIntent(intent: Intent) {
|
||||
if (!isSwapIntent(intent)) {
|
||||
return
|
||||
}
|
||||
|
||||
pendingRomSwapIntent = Intent(intent)
|
||||
|
||||
if (!isWaitingForRomSwapStop) {
|
||||
Log.info("[EmulationActivity] Begin ROM swap: data=${intent.data}")
|
||||
isWaitingForRomSwapStop = true
|
||||
romSwapNativeStopped = false
|
||||
romSwapThreadStopped = false
|
||||
romSwapGeneration += 1
|
||||
val thisSwapGeneration = romSwapGeneration
|
||||
emulationViewModel.setIsEmulationStopping(true)
|
||||
emulationViewModel.setEmulationStopped(false)
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
|
||||
val childFragmentManager = navHostFragment?.childFragmentManager
|
||||
val stoppingFragmentForSwap =
|
||||
(childFragmentManager?.primaryNavigationFragment as? EmulationFragment) ?:
|
||||
childFragmentManager
|
||||
?.fragments
|
||||
?.asReversed()
|
||||
?.firstOrNull {
|
||||
it is EmulationFragment &&
|
||||
it.isAdded &&
|
||||
it.view != null &&
|
||||
!it.isRemoving
|
||||
} as? EmulationFragment
|
||||
|
||||
val hasSessionForSwap = hasEmulationSession || stoppingFragmentForSwap != null
|
||||
|
||||
if (!hasSessionForSwap) {
|
||||
romSwapNativeStopped = true
|
||||
romSwapThreadStopped = true
|
||||
} else {
|
||||
if (stoppingFragmentForSwap != null) {
|
||||
stoppingFragmentForSwap.stopForRomSwap()
|
||||
stoppingFragmentForSwap.notifyWhenEmulationThreadStops {
|
||||
if (!isWaitingForRomSwapStop || romSwapGeneration != thisSwapGeneration) {
|
||||
return@notifyWhenEmulationThreadStops
|
||||
}
|
||||
romSwapThreadStopped = true
|
||||
Log.info("[EmulationActivity] ROM swap thread stop acknowledged")
|
||||
launchPendingRomSwap(force = false)
|
||||
}
|
||||
} else {
|
||||
Log.warning("[EmulationActivity] ROM swap stop target fragment not found; requesting native stop")
|
||||
romSwapThreadStopped = true
|
||||
NativeLibrary.stopEmulation()
|
||||
}
|
||||
|
||||
scheduleRomSwapStopTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
launchPendingRomSwap(force = false)
|
||||
}
|
||||
|
||||
private fun launchPendingRomSwap(force: Boolean) {
|
||||
if (!isWaitingForRomSwapStop) {
|
||||
return
|
||||
}
|
||||
if (!force && (!romSwapNativeStopped || !romSwapThreadStopped)) {
|
||||
return
|
||||
}
|
||||
val swapIntent = pendingRomSwapIntent ?: return
|
||||
Log.info("[EmulationActivity] Launching pending ROM swap: data=${swapIntent.data}")
|
||||
pendingRomSwapIntent = null
|
||||
isWaitingForRomSwapStop = false
|
||||
romSwapNativeStopped = false
|
||||
romSwapThreadStopped = false
|
||||
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
|
||||
applyGameLaunchIntent(swapIntent)
|
||||
}
|
||||
|
||||
private fun applyGameLaunchIntent(intent: Intent) {
|
||||
hasEmulationSession = true
|
||||
processHasEmulationSession = true
|
||||
emulationViewModel.setIsEmulationStopping(false)
|
||||
emulationViewModel.setEmulationStopped(false)
|
||||
setIntent(Intent(intent))
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
|
||||
val navController = navHostFragment.navController
|
||||
val startArgs = intent.extras?.let { Bundle(it) } ?: Bundle()
|
||||
val navOptions = NavOptions.Builder()
|
||||
.setPopUpTo(R.id.emulationFragment, true)
|
||||
.build()
|
||||
|
||||
runCatching {
|
||||
navController.navigate(R.id.emulationFragment, startArgs, navOptions)
|
||||
}.onFailure {
|
||||
Log.warning("[EmulationActivity] ROM swap navigate fallback to setGraph: ${it.message}")
|
||||
navController.setGraph(R.navigation.emulation_navigation, startArgs)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
|
||||
if (event.keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
||||
@@ -608,19 +762,48 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
}
|
||||
|
||||
fun onEmulationStarted() {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post { onEmulationStarted() }
|
||||
return
|
||||
}
|
||||
hasEmulationSession = true
|
||||
processHasEmulationSession = true
|
||||
emulationViewModel.setEmulationStarted(true)
|
||||
emulationViewModel.setIsEmulationStopping(false)
|
||||
emulationViewModel.setEmulationStopped(false)
|
||||
NativeLibrary.playTimeManagerStart()
|
||||
|
||||
}
|
||||
|
||||
fun onEmulationStopped(status: Int) {
|
||||
if (status == 0 && emulationViewModel.programChanged.value == -1) {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post { onEmulationStopped(status) }
|
||||
return
|
||||
}
|
||||
hasEmulationSession = false
|
||||
processHasEmulationSession = false
|
||||
if (isWaitingForRomSwapStop) {
|
||||
romSwapNativeStopped = true
|
||||
Log.info("[EmulationActivity] ROM swap native stop acknowledged")
|
||||
launchPendingRomSwap(force = false)
|
||||
} else if (status == 0 && emulationViewModel.programChanged.value == -1) {
|
||||
processSessionGame = null
|
||||
finish()
|
||||
} else if (!isWaitingForRomSwapStop) {
|
||||
processSessionGame = null
|
||||
}
|
||||
emulationViewModel.setEmulationStopped(true)
|
||||
}
|
||||
|
||||
fun updateSessionGame(game: Game?) {
|
||||
processSessionGame = game
|
||||
}
|
||||
|
||||
fun onProgramChanged(programIndex: Int) {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post { onProgramChanged(programIndex) }
|
||||
return
|
||||
}
|
||||
emulationViewModel.setProgramChanged(programIndex)
|
||||
}
|
||||
|
||||
@@ -644,6 +827,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
companion object {
|
||||
const val EXTRA_SELECTED_GAME = "SelectedGame"
|
||||
const val EXTRA_OVERLAY_GAMELESS_EDIT_MODE = "overlayGamelessEditMode"
|
||||
private const val ROM_SWAP_STOP_TIMEOUT_MS = 5000L
|
||||
@Volatile
|
||||
private var processHasEmulationSession = false
|
||||
@Volatile
|
||||
private var processSessionGame: Game? = null
|
||||
|
||||
fun stopForegroundService(activity: Activity) {
|
||||
val startIntent = Intent(activity, ForegroundService::class.java)
|
||||
|
||||
@@ -50,6 +50,7 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.window.layout.FoldingFeature
|
||||
import androidx.window.layout.WindowInfoTracker
|
||||
@@ -135,6 +136,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
private var intentGame: Game? = null
|
||||
private var isCustomSettingsIntent = false
|
||||
private var isStoppingForRomSwap = false
|
||||
private var deferGameSetupUntilStopCompletes = false
|
||||
|
||||
private var perfStatsRunnable: Runnable? = null
|
||||
private var socRunnable: Runnable? = null
|
||||
@@ -238,6 +241,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
if (emulationViewModel.isEmulationStopping.value) {
|
||||
deferGameSetupUntilStopCompletes = true
|
||||
if (game == null) {
|
||||
game = args.game ?: intentGame
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
finishGameSetup()
|
||||
}
|
||||
|
||||
@@ -260,6 +271,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
game = gameToUse
|
||||
emulationActivity?.updateSessionGame(gameToUse)
|
||||
} catch (e: Exception) {
|
||||
Log.error("[EmulationFragment] Error during game setup: ${e.message}")
|
||||
Toast.makeText(
|
||||
@@ -334,7 +346,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
emulationState = EmulationState(game!!.path) {
|
||||
return@EmulationState driverViewModel.isInteractionAllowed.value
|
||||
return@EmulationState driverViewModel.isInteractionAllowed.value &&
|
||||
!isStoppingForRomSwap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -890,8 +903,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
)
|
||||
|
||||
GameIconUtils.loadGameIcon(game!!, binding.loadingImage)
|
||||
binding.loadingTitle.text = game!!.title
|
||||
game?.let {
|
||||
GameIconUtils.loadGameIcon(it, binding.loadingImage)
|
||||
binding.loadingTitle.text = it.title
|
||||
} ?: run {
|
||||
binding.loadingTitle.text = ""
|
||||
}
|
||||
binding.loadingTitle.isSelected = true
|
||||
binding.loadingText.isSelected = true
|
||||
|
||||
@@ -959,6 +976,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
ViewUtils.showView(binding.loadingIndicator)
|
||||
ViewUtils.hideView(binding.inputContainer)
|
||||
ViewUtils.hideView(binding.showStatsOverlayText)
|
||||
} else if (deferGameSetupUntilStopCompletes) {
|
||||
if (!isAdded) {
|
||||
return@collect
|
||||
}
|
||||
deferGameSetupUntilStopCompletes = false
|
||||
finishGameSetup()
|
||||
}
|
||||
}
|
||||
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
|
||||
@@ -995,26 +1018,24 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
|
||||
if (it && !NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
||||
startEmulation()
|
||||
if (it &&
|
||||
!isStoppingForRomSwap &&
|
||||
!NativeLibrary.isRunning() &&
|
||||
!NativeLibrary.isPaused()
|
||||
) {
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
DirectoryInitialization.start()
|
||||
}
|
||||
|
||||
updateScreenLayout()
|
||||
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated)
|
||||
}
|
||||
}
|
||||
|
||||
driverViewModel.onLaunchGame()
|
||||
}
|
||||
|
||||
private fun startEmulation(programIndex: Int = 0) {
|
||||
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
DirectoryInitialization.start()
|
||||
}
|
||||
|
||||
updateScreenLayout()
|
||||
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated, programIndex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
val b = _binding ?: return
|
||||
@@ -1375,6 +1396,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
super.onDestroyView()
|
||||
amiiboLoadJob?.cancel()
|
||||
amiiboLoadJob = null
|
||||
perfStatsRunnable?.let { perfStatsUpdateHandler.removeCallbacks(it) }
|
||||
socRunnable?.let { socUpdateHandler.removeCallbacks(it) }
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
clearPausedFrame()
|
||||
_binding?.surfaceInputOverlay?.touchEventListener = null
|
||||
_binding = null
|
||||
@@ -1382,7 +1406,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
NativeLibrary.clearEmulationActivity()
|
||||
if (!hasNewerEmulationFragment()) {
|
||||
NativeLibrary.clearEmulationActivity()
|
||||
}
|
||||
super.onDetach()
|
||||
}
|
||||
|
||||
@@ -1840,10 +1866,74 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
emulationState.clearSurface()
|
||||
if (this::emulationState.isInitialized && !hasNewerEmulationFragment()) {
|
||||
emulationState.clearSurface()
|
||||
}
|
||||
emulationStarted = false
|
||||
}
|
||||
|
||||
private fun hasNewerEmulationFragment(): Boolean {
|
||||
val activity = emulationActivity ?: return false
|
||||
return try {
|
||||
val navHostFragment =
|
||||
activity.supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
|
||||
?: return false
|
||||
val currentFragment = navHostFragment.childFragmentManager.fragments
|
||||
.filterIsInstance<EmulationFragment>()
|
||||
.firstOrNull()
|
||||
currentFragment != null && currentFragment !== this
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// xbzk: called from EmulationActivity when a new game is loaded while this fragment is still active,
|
||||
// to wait for the emulation thread to stop before allowing the ROM swap to proceed
|
||||
fun notifyWhenEmulationThreadStops(onStopped: () -> Unit) {
|
||||
if (!this::emulationState.isInitialized) {
|
||||
onStopped()
|
||||
return
|
||||
}
|
||||
val emuThread = runCatching { emulationState.emulationThread }.getOrNull()
|
||||
if (emuThread == null || !emuThread.isAlive) {
|
||||
onStopped()
|
||||
return
|
||||
}
|
||||
Thread({
|
||||
runCatching { emuThread.join() }
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
onStopped()
|
||||
}
|
||||
}, "RomSwapWait").start()
|
||||
}
|
||||
|
||||
// xbzk: called from EmulationActivity when a new game is loaded while this
|
||||
// fragment is still active, to stop the current emulation before swapping the ROM
|
||||
fun stopForRomSwap() {
|
||||
if (isStoppingForRomSwap) {
|
||||
return
|
||||
}
|
||||
isStoppingForRomSwap = true
|
||||
clearPausedFrame()
|
||||
emulationViewModel.setIsEmulationStopping(true)
|
||||
_binding?.let {
|
||||
binding.loadingText.setText(R.string.shutting_down)
|
||||
ViewUtils.showView(binding.loadingIndicator)
|
||||
ViewUtils.hideView(binding.inputContainer)
|
||||
ViewUtils.hideView(binding.showStatsOverlayText)
|
||||
}
|
||||
if (this::emulationState.isInitialized) {
|
||||
emulationState.stop()
|
||||
if (NativeLibrary.isRunning() || NativeLibrary.isPaused()) {
|
||||
Log.warning("[EmulationFragment] ROM swap stop fallback: forcing native stop request.")
|
||||
NativeLibrary.stopEmulation()
|
||||
}
|
||||
} else {
|
||||
NativeLibrary.stopEmulation()
|
||||
}
|
||||
NativeConfig.reloadGlobalConfig()
|
||||
}
|
||||
|
||||
private fun showOverlayOptions() {
|
||||
val anchor = binding.inGameMenu.findViewById<View>(R.id.menu_overlay_controls)
|
||||
val popup = PopupMenu(requireContext(), anchor)
|
||||
@@ -2134,6 +2224,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
state = State.STOPPED
|
||||
} else {
|
||||
Log.warning("[EmulationFragment] Stop called while already stopped.")
|
||||
NativeLibrary.stopEmulation()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGamePropertiesBinding
|
||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsSubscreen
|
||||
import org.yuzu.yuzu_emu.model.AddonViewModel
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.GameProperty
|
||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||
@@ -46,6 +47,7 @@ import org.yuzu.yuzu_emu.model.SubmenuProperty
|
||||
import org.yuzu.yuzu_emu.model.TaskState
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||
import org.yuzu.yuzu_emu.utils.GameIconUtils
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
||||
@@ -61,6 +63,7 @@ class GamePropertiesFragment : Fragment() {
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
private val gamesViewModel: GamesViewModel by activityViewModels()
|
||||
private val addonViewModel: AddonViewModel by activityViewModels()
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
|
||||
private val args by navArgs<GamePropertiesFragmentArgs>()
|
||||
@@ -118,6 +121,20 @@ class GamePropertiesFragment : Fragment() {
|
||||
.show(childFragmentManager, LaunchGameDialogFragment.TAG)
|
||||
}
|
||||
|
||||
if (GameHelper.cachedGameList.isEmpty()) {
|
||||
binding.buttonStart.isEnabled = false
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
GameHelper.restoreContentForGame(args.game)
|
||||
}
|
||||
if (_binding == null) {
|
||||
return@launch
|
||||
}
|
||||
addonViewModel.onAddonsViewStarted(args.game)
|
||||
binding.buttonStart.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
reloadList()
|
||||
|
||||
homeViewModel.openImportSaves.collect(
|
||||
|
||||
@@ -100,42 +100,45 @@ class GamesViewModel : ViewModel() {
|
||||
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (firstStartup) {
|
||||
// Retrieve list of cached games
|
||||
val storedGames =
|
||||
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
.getStringSet(GameHelper.KEY_GAMES, emptySet())
|
||||
if (storedGames!!.isNotEmpty()) {
|
||||
val deserializedGames = mutableSetOf<Game>()
|
||||
storedGames.forEach {
|
||||
val game: Game
|
||||
try {
|
||||
game = Json.decodeFromString(it)
|
||||
} catch (e: Exception) {
|
||||
// We don't care about any errors related to parsing the game cache
|
||||
return@forEach
|
||||
}
|
||||
try {
|
||||
if (firstStartup) {
|
||||
// Retrieve list of cached games
|
||||
val storedGames =
|
||||
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
.getStringSet(GameHelper.KEY_GAMES, emptySet())
|
||||
if (storedGames!!.isNotEmpty()) {
|
||||
val deserializedGames = mutableSetOf<Game>()
|
||||
storedGames.forEach {
|
||||
val game: Game
|
||||
try {
|
||||
game = Json.decodeFromString(it)
|
||||
} catch (e: Exception) {
|
||||
// We don't care about any errors related to parsing the game cache
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val gameExists =
|
||||
DocumentFile.fromSingleUri(
|
||||
YuzuApplication.appContext,
|
||||
Uri.parse(game.path)
|
||||
)?.exists()
|
||||
if (gameExists == true) {
|
||||
deserializedGames.add(game)
|
||||
val gameExists =
|
||||
DocumentFile.fromSingleUri(
|
||||
YuzuApplication.appContext,
|
||||
Uri.parse(game.path)
|
||||
)?.exists()
|
||||
if (gameExists == true) {
|
||||
deserializedGames.add(game)
|
||||
}
|
||||
}
|
||||
setGames(deserializedGames.toList())
|
||||
}
|
||||
setGames(deserializedGames.toList())
|
||||
}
|
||||
}
|
||||
|
||||
setGames(GameHelper.getGames())
|
||||
reloading.set(false)
|
||||
_isReloading.value = false
|
||||
_shouldScrollAfterReload.value = true
|
||||
setGames(GameHelper.getGames())
|
||||
_shouldScrollAfterReload.value = true
|
||||
|
||||
if (directoriesChanged) {
|
||||
setShouldSwapData(true)
|
||||
if (directoriesChanged) {
|
||||
setShouldSwapData(true)
|
||||
}
|
||||
} finally {
|
||||
reloading.set(false)
|
||||
_isReloading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ object DirectoryInitialization {
|
||||
fun start() {
|
||||
if (!areDirectoriesReady) {
|
||||
initializeInternalStorage()
|
||||
NativeLibrary.initializeSystem(false)
|
||||
NativeConfig.initializeGlobalConfig()
|
||||
NativeLibrary.initializeSystem(false)
|
||||
NativeLibrary.reloadProfiles()
|
||||
migrateSettings()
|
||||
areDirectoriesReady = true
|
||||
|
||||
@@ -8,9 +8,11 @@ package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.provider.DocumentsContract
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
@@ -49,29 +51,8 @@ object GameHelper {
|
||||
// Remove previous filesystem provider information so we can get up to date version info
|
||||
NativeLibrary.clearFilesystemProvider()
|
||||
|
||||
// Scan External Content directories and register all NSP/XCI files
|
||||
val externalContentDirs = NativeConfig.getExternalContentDirs()
|
||||
val uniqueExternalContentDirs = linkedSetOf<String>()
|
||||
externalContentDirs.forEach { externalDir ->
|
||||
if (externalDir.isNotEmpty()) {
|
||||
uniqueExternalContentDirs.add(externalDir)
|
||||
}
|
||||
}
|
||||
|
||||
val mountedContainerUris = mutableSetOf<String>()
|
||||
for (externalDir in uniqueExternalContentDirs) {
|
||||
if (externalDir.isNotEmpty()) {
|
||||
val externalDirUri = externalDir.toUri()
|
||||
if (FileUtil.isTreeUriValid(externalDirUri)) {
|
||||
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
|
||||
val containerUri = it.uri.toString()
|
||||
if (mountedContainerUris.add(containerUri)) {
|
||||
NativeLibrary.addFileToFilesystemProvider(containerUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mountExternalContentDirectories(mountedContainerUris)
|
||||
|
||||
val badDirs = mutableListOf<Int>()
|
||||
gameDirs.forEachIndexed { index: Int, gameDir: GameDir ->
|
||||
@@ -115,6 +96,15 @@ object GameHelper {
|
||||
return games.toList()
|
||||
}
|
||||
|
||||
fun restoreContentForGame(game: Game) {
|
||||
NativeLibrary.reloadKeys()
|
||||
|
||||
val mountedContainerUris = mutableSetOf<String>()
|
||||
mountExternalContentDirectories(mountedContainerUris)
|
||||
mountGameFolderContent(Uri.parse(game.path), mountedContainerUris)
|
||||
NativeLibrary.addFileToFilesystemProvider(game.path)
|
||||
}
|
||||
|
||||
// File extensions considered as external content, buuut should
|
||||
// be done better imo.
|
||||
private val externalContentExtensions = setOf("nsp", "xci")
|
||||
@@ -181,6 +171,71 @@ object GameHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private fun mountExternalContentDirectories(mountedContainerUris: MutableSet<String>) {
|
||||
val uniqueExternalContentDirs = linkedSetOf<String>()
|
||||
NativeConfig.getExternalContentDirs().forEach { externalDir ->
|
||||
if (externalDir.isNotEmpty()) {
|
||||
uniqueExternalContentDirs.add(externalDir)
|
||||
}
|
||||
}
|
||||
|
||||
for (externalDir in uniqueExternalContentDirs) {
|
||||
val externalDirUri = externalDir.toUri()
|
||||
if (FileUtil.isTreeUriValid(externalDirUri)) {
|
||||
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
|
||||
val containerUri = it.uri.toString()
|
||||
if (mountedContainerUris.add(containerUri)) {
|
||||
NativeLibrary.addFileToFilesystemProvider(containerUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mountGameFolderContent(gameUri: Uri, mountedContainerUris: MutableSet<String>) {
|
||||
if (gameUri.scheme == "content") {
|
||||
val parentUri = getParentDocumentUri(gameUri) ?: return
|
||||
scanContentContainersRecursive(FileUtil.listFiles(parentUri), 1) {
|
||||
val containerUri = it.uri.toString()
|
||||
if (mountedContainerUris.add(containerUri)) {
|
||||
NativeLibrary.addGameFolderFileToFilesystemProvider(containerUri)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val gameFile = File(gameUri.path ?: gameUri.toString())
|
||||
val parentDir = gameFile.parentFile ?: return
|
||||
parentDir.listFiles()?.forEach { sibling ->
|
||||
if (!sibling.isFile) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val extension = sibling.extension.lowercase()
|
||||
if (externalContentExtensions.contains(extension)) {
|
||||
val containerUri = Uri.fromFile(sibling).toString()
|
||||
if (mountedContainerUris.add(containerUri)) {
|
||||
NativeLibrary.addGameFolderFileToFilesystemProvider(containerUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getParentDocumentUri(uri: Uri): Uri? {
|
||||
return try {
|
||||
val documentId = DocumentsContract.getDocumentId(uri)
|
||||
val separatorIndex = documentId.lastIndexOf('/')
|
||||
if (separatorIndex == -1) {
|
||||
null
|
||||
} else {
|
||||
val parentDocumentId = documentId.substring(0, separatorIndex)
|
||||
DocumentsContract.buildDocumentUriUsingTree(uri, parentDocumentId)
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getGame(
|
||||
uri: Uri,
|
||||
addedToLibrary: Boolean,
|
||||
|
||||
@@ -134,6 +134,8 @@ add_library(
|
||||
typed_address.h
|
||||
uint128.h
|
||||
unique_function.h
|
||||
random.cpp
|
||||
random.h
|
||||
uuid.cpp
|
||||
uuid.h
|
||||
vector_math.h
|
||||
|
||||
@@ -30,12 +30,9 @@ MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bit
|
||||
void* base{VirtualAlloc(nullptr, alloc_size, MEM_RESERVE, PAGE_READWRITE)};
|
||||
#else
|
||||
void* base{mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)};
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
if (base == MAP_FAILED)
|
||||
base = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(base);
|
||||
base_ptr = reinterpret_cast<BaseAddr*>(base);
|
||||
}
|
||||
@@ -56,29 +53,21 @@ template <typename BaseAddr>
|
||||
void MultiLevelPageTable<BaseAddr>::ReserveRange(u64 start, std::size_t size) {
|
||||
const u64 new_start = start >> first_level_shift;
|
||||
const u64 new_end = (start + size) >> first_level_shift;
|
||||
for (u64 i = new_start; i <= new_end; i++) {
|
||||
if (!first_level_map[i]) {
|
||||
for (u64 i = new_start; i <= new_end; i++)
|
||||
if (!first_level_map[i])
|
||||
AllocateLevel(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BaseAddr>
|
||||
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 level) {
|
||||
void* ptr = reinterpret_cast<char *>(base_ptr) + level * first_level_chunk_size;
|
||||
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 index) {
|
||||
void* ptr = reinterpret_cast<char *>(base_ptr) + index * first_level_chunk_size;
|
||||
#ifdef _WIN32
|
||||
void* base{VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE)};
|
||||
#else
|
||||
void* base{mmap(ptr, first_level_chunk_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)};
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
base = nullptr;
|
||||
}
|
||||
#endif
|
||||
void* base = VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE);
|
||||
ASSERT(base);
|
||||
|
||||
first_level_map[level] = base;
|
||||
#else
|
||||
void* base = ptr;
|
||||
#endif
|
||||
first_level_map[index] = base;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include "common/random.h"
|
||||
|
||||
namespace Common::Random {
|
||||
[[nodiscard]] static std::random_device& GetGlobalRandomDevice() noexcept {
|
||||
static std::random_device g_random_device{};
|
||||
return g_random_device;
|
||||
}
|
||||
[[nodiscard]] u32 Random32(u32 seed) noexcept {
|
||||
return GetGlobalRandomDevice()();
|
||||
}
|
||||
[[nodiscard]] u64 Random64(u64 seed) noexcept {
|
||||
return GetGlobalRandomDevice()();
|
||||
}
|
||||
[[nodiscard]] std::mt19937 GetMT19937() noexcept {
|
||||
return std::mt19937(GetGlobalRandomDevice()());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Random {
|
||||
[[nodiscard]] u32 Random32(u32 seed) noexcept;
|
||||
[[nodiscard]] u64 Random64(u64 seed) noexcept;
|
||||
[[nodiscard]] std::mt19937 GetMT19937() noexcept;
|
||||
}
|
||||
@@ -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
|
||||
@@ -218,12 +218,6 @@ public:
|
||||
return t0;
|
||||
}
|
||||
|
||||
u64 GenerateRandomU64() {
|
||||
const u32 lo = this->GenerateRandomU32();
|
||||
const u32 hi = this->GenerateRandomU32();
|
||||
return (u64{hi} << 32) | u64{lo};
|
||||
}
|
||||
|
||||
float GenerateRandomF32() {
|
||||
// Floats have 24 bits of mantissa.
|
||||
constexpr u32 MantissaBits = 24;
|
||||
|
||||
+5
-6
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -10,6 +13,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/tiny_mt.h"
|
||||
#include "common/uuid.h"
|
||||
#include "common/random.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
@@ -175,21 +179,16 @@ u128 UUID::AsU128() const {
|
||||
}
|
||||
|
||||
UUID UUID::MakeRandom() {
|
||||
std::random_device device;
|
||||
|
||||
return MakeRandomWithSeed(device());
|
||||
return MakeRandomWithSeed(Common::Random::Random32(0));
|
||||
}
|
||||
|
||||
UUID UUID::MakeRandomWithSeed(u32 seed) {
|
||||
// Create and initialize our RNG.
|
||||
TinyMT rng;
|
||||
rng.Initialize(seed);
|
||||
|
||||
UUID uuid;
|
||||
|
||||
// Populate the UUID with random bytes.
|
||||
rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(UUID));
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/random.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
@@ -490,17 +491,13 @@ std::vector<NcaID> PlaceholderCache::List() const {
|
||||
}
|
||||
|
||||
NcaID PlaceholderCache::Generate() {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
auto gen = Common::Random::GetMT19937();
|
||||
std::uniform_int_distribution<u64> distribution(1, (std::numeric_limits<u64>::max)());
|
||||
|
||||
NcaID out{};
|
||||
|
||||
const auto v1 = distribution(gen);
|
||||
const auto v2 = distribution(gen);
|
||||
std::memcpy(out.data(), &v1, sizeof(u64));
|
||||
std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <random>
|
||||
|
||||
#include "common/literals.h"
|
||||
#include "common/random.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
|
||||
@@ -201,15 +202,8 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
u64 KSystemControl::GenerateRandomU64() {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u64> distribution(1, (std::numeric_limits<u64>::max)());
|
||||
return distribution(gen);
|
||||
}
|
||||
|
||||
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64);
|
||||
return GenerateUniformRange(min, max, Common::Random::GetMT19937());
|
||||
}
|
||||
|
||||
size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -33,7 +36,6 @@ public:
|
||||
|
||||
// Randomness.
|
||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||
static u64 GenerateRandomU64();
|
||||
|
||||
// Secure Memory.
|
||||
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool);
|
||||
|
||||
@@ -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
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/tiny_mt.h"
|
||||
#include "common/random.h"
|
||||
#include "core/hle/kernel/k_system_control.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -23,7 +24,7 @@ public:
|
||||
class RandomBitGenerator {
|
||||
public:
|
||||
RandomBitGenerator() {
|
||||
m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
|
||||
m_rng.Initialize(u32(Common::Random::Random64(0)));
|
||||
}
|
||||
|
||||
u64 SelectRandomBit(u64 bitmap) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "common/fiber.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/random.h"
|
||||
#include "core/core.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/hardware_properties.h"
|
||||
@@ -45,8 +46,7 @@ namespace {
|
||||
|
||||
constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
|
||||
|
||||
static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
|
||||
u64 arg) {
|
||||
static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, u64 arg) {
|
||||
ctx = {};
|
||||
ctx.r[0] = arg;
|
||||
ctx.r[15] = entry_point;
|
||||
@@ -55,11 +55,10 @@ static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top,
|
||||
ctx.fpsr = 0;
|
||||
}
|
||||
|
||||
static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
|
||||
u64 arg) {
|
||||
static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, u64 arg) {
|
||||
ctx = {};
|
||||
ctx.r[0] = arg;
|
||||
ctx.r[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
|
||||
ctx.r[18] = Common::Random::Random64(0) | 1;
|
||||
ctx.pc = entry_point;
|
||||
ctx.sp = stack_top;
|
||||
ctx.fpcr = 0;
|
||||
|
||||
@@ -438,20 +438,20 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
|
||||
|
||||
template <bool Domain, typename T, typename... A>
|
||||
void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
|
||||
const auto mgr = ctx.GetManager().get();
|
||||
// Verify domain state.
|
||||
if constexpr (!Domain) {
|
||||
const auto _mgr = ctx.GetManager();
|
||||
const bool _is_domain = _mgr ? _mgr->IsDomain() : false;
|
||||
ASSERT_MSG(!_is_domain,
|
||||
"Non-domain reply used on domain session\n"
|
||||
"Service={} (TIPC={} CmdType={} Cmd=0x{:08X}\n"
|
||||
"HasDomainHeader={} DomainHandlers={}\nDesc={}",
|
||||
t.GetServiceName(), ctx.IsTipc(),
|
||||
static_cast<u32>(ctx.GetCommandType()), static_cast<u32>(ctx.GetCommand()),
|
||||
ctx.HasDomainMessageHeader(), _mgr ? static_cast<u32>(_mgr->DomainHandlerCount()) : 0u,
|
||||
ctx.Description());
|
||||
const bool is_domain = mgr ? mgr->IsDomain() : false;
|
||||
ASSERT_MSG(!is_domain,
|
||||
"Non-domain reply used on domain session\n"
|
||||
"Service={} (TIPC={} CmdType={} Cmd=0x{:08X}\n"
|
||||
"HasDomainHeader={} DomainHandlers={}\nDesc={}",
|
||||
t.GetServiceName(), ctx.IsTipc(),
|
||||
u32(ctx.GetCommandType()), u32(ctx.GetCommand()),
|
||||
ctx.HasDomainMessageHeader(), mgr ? u32(mgr->DomainHandlerCount()) : 0u,
|
||||
ctx.Description());
|
||||
}
|
||||
const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
|
||||
const bool is_domain = Domain ? mgr->IsDomain() : false;
|
||||
|
||||
static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
|
||||
using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -78,32 +81,29 @@ public:
|
||||
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
|
||||
|
||||
IPC::CommandHeader header{};
|
||||
auto const mgr = ctx.GetManager().get();
|
||||
|
||||
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
|
||||
// padding.
|
||||
u32 raw_data_size = ctx.write_size =
|
||||
ctx.IsTipc() ? normal_params_size - 1 : normal_params_size;
|
||||
u32 raw_data_size = ctx.write_size = ctx.IsTipc() ? normal_params_size - 1 : normal_params_size;
|
||||
u32 num_handles_to_move{};
|
||||
u32 num_domain_objects{};
|
||||
const bool always_move_handles{
|
||||
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
|
||||
if (!ctx.GetManager()->IsDomain() || always_move_handles) {
|
||||
const bool always_move_handles = (u32(flags) & u32(Flags::AlwaysMoveHandles)) != 0;
|
||||
if (!mgr->IsDomain() || always_move_handles) {
|
||||
num_handles_to_move = num_objects_to_move;
|
||||
} else {
|
||||
num_domain_objects = num_objects_to_move;
|
||||
}
|
||||
|
||||
if (ctx.GetManager()->IsDomain()) {
|
||||
raw_data_size +=
|
||||
static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
|
||||
if (mgr->IsDomain()) {
|
||||
raw_data_size += u32(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
|
||||
ctx.write_size += num_domain_objects;
|
||||
}
|
||||
|
||||
if (ctx.IsTipc()) {
|
||||
header.type.Assign(ctx.GetCommandType());
|
||||
} else {
|
||||
raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 +
|
||||
normal_params_size);
|
||||
raw_data_size += u32(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + normal_params_size);
|
||||
}
|
||||
|
||||
header.data_size.Assign(raw_data_size);
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
if (!ctx.IsTipc()) {
|
||||
AlignWithPadding();
|
||||
|
||||
if (ctx.GetManager()->IsDomain() && ctx.HasDomainMessageHeader()) {
|
||||
if (mgr->IsDomain() && ctx.HasDomainMessageHeader()) {
|
||||
IPC::DomainMessageHeader domain_header{};
|
||||
domain_header.num_objects = num_domain_objects;
|
||||
PushRaw(domain_header);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -7,6 +10,7 @@
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/random.h"
|
||||
#include "common/swap.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/mii/mii_types.h"
|
||||
@@ -65,11 +69,9 @@ public:
|
||||
|
||||
template <typename T>
|
||||
static T GetRandomValue(T min, T max) {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u64> distribution(static_cast<u64>(min),
|
||||
static_cast<u64>(max));
|
||||
return static_cast<T>(distribution(gen));
|
||||
std::uniform_int_distribution<u64> distribution{u64(min), u64(max)};
|
||||
auto gen = Common::Random::GetMT19937();
|
||||
return T(distribution(gen));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include "common/logging.h"
|
||||
#include "common/random.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
@@ -229,7 +230,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include "common/settings.h"
|
||||
#include "common/random.h"
|
||||
#include "core/file_sys/kernel_executable.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
@@ -90,7 +91,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset, false).IsError()) {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/random.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
@@ -243,7 +244,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process
|
||||
|
||||
+2
-12
@@ -45,11 +45,7 @@ static inline bool AddressSpaceContains(const Common::PageTable& table, const Co
|
||||
// from outside classes. This also allows modification to the internals of the memory
|
||||
// subsystem without needing to rebuild all files that make use of the memory interface.
|
||||
struct Memory::Impl {
|
||||
explicit Impl(Core::System& system_) : system{system_} {
|
||||
// Initialize thread count based on available cores for parallel memory operations
|
||||
const unsigned int hw_concurrency = std::thread::hardware_concurrency();
|
||||
thread_count = (std::max)(2u, (std::min)(hw_concurrency, 8u)); // Limit to 8 threads max
|
||||
}
|
||||
explicit Impl(Core::System& system_) : system{system_} {}
|
||||
|
||||
void SetCurrentPageTable(Kernel::KProcess& process) {
|
||||
current_page_table = &process.GetPageTable().GetImpl();
|
||||
@@ -856,13 +852,7 @@ struct Memory::Impl {
|
||||
Tegra::MaxwellDeviceMemoryManager* gpu_device_memory{};
|
||||
Common::PageTable* current_page_table = nullptr;
|
||||
|
||||
// Number of threads to use for parallel memory operations
|
||||
unsigned int thread_count = 2;
|
||||
|
||||
// Minimum size in bytes for which parallel processing is beneficial
|
||||
//size_t PARALLEL_THRESHOLD = (L3 CACHE * NUM PHYSICAL CORES); // 64 KB
|
||||
std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
|
||||
rasterizer_read_areas{};
|
||||
std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> rasterizer_read_areas{};
|
||||
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
|
||||
std::array<Common::ScratchBuffer<u32>, Core::Hardware::NUM_CPU_CORES> scratch_buffers{};
|
||||
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -59,8 +59,10 @@ static Xbyak::Address MJitStateExtReg(A32::ExtReg reg) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
A32EmitContext::A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block)
|
||||
: EmitContext(reg_alloc, block), conf(conf) {}
|
||||
A32EmitContext::A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels)
|
||||
: EmitContext(reg_alloc, block, shared_labels)
|
||||
, conf(conf)
|
||||
{}
|
||||
|
||||
A32::LocationDescriptor A32EmitContext::Location() const {
|
||||
return A32::LocationDescriptor{block.Location()};
|
||||
@@ -109,35 +111,59 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
||||
gprs.reset(size_t(HostLoc::R14));
|
||||
return gprs;
|
||||
}(), any_xmm);
|
||||
A32EmitContext ctx{conf, reg_alloc, block};
|
||||
|
||||
A32EmitContext ctx{conf, reg_alloc, block, shared_labels};
|
||||
|
||||
// Start emitting.
|
||||
code.align();
|
||||
const u8* const entrypoint = code.getCurr();
|
||||
code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp);
|
||||
code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]);
|
||||
|
||||
EmitCondPrelude(ctx);
|
||||
|
||||
for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) [[likely]] {
|
||||
auto* inst = &*iter;
|
||||
// Call the relevant Emit* member function.
|
||||
switch (inst->GetOpcode()) {
|
||||
#define OPCODE(name, type, ...) \
|
||||
case IR::Opcode::name: \
|
||||
A32EmitX64::Emit##name(ctx, inst); \
|
||||
break;
|
||||
#define A32OPC(name, type, ...) \
|
||||
case IR::Opcode::A32##name: \
|
||||
A32EmitX64::EmitA32##name(ctx, inst);\
|
||||
break;
|
||||
typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst);
|
||||
constexpr EmitHandlerFn opcode_handlers[] = {
|
||||
#define OPCODE(name, type, ...) &EmitX64::Emit##name,
|
||||
#define A32OPC(name, type, ...)
|
||||
#define A64OPC(name, type, ...)
|
||||
#include "dynarmic/ir/opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
};
|
||||
typedef void (A32EmitX64::*A32EmitHandlerFn)(A32EmitContext& context, IR::Inst* inst);
|
||||
constexpr A32EmitHandlerFn a32_handlers[] = {
|
||||
#define OPCODE(...)
|
||||
#define A32OPC(name, type, ...) &A32EmitX64::EmitA32##name,
|
||||
#define A64OPC(...)
|
||||
#include "dynarmic/ir/opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
};
|
||||
|
||||
for (auto& inst : block.instructions) {
|
||||
auto const opcode = inst.GetOpcode();
|
||||
// Call the relevant Emit* member function.
|
||||
switch (opcode) {
|
||||
#define OPCODE(name, type, ...) case IR::Opcode::name: goto opcode_branch;
|
||||
#define A32OPC(name, type, ...) case IR::Opcode::A32##name: goto a32_branch;
|
||||
#define A64OPC(name, type, ...)
|
||||
#include "dynarmic/ir/opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
reg_alloc.EndOfAllocScope();
|
||||
opcode_branch:
|
||||
(this->*opcode_handlers[size_t(opcode)])(ctx, &inst);
|
||||
goto finish_this_inst;
|
||||
a32_branch:
|
||||
// Update with FIRST A32 instruction
|
||||
(this->*a32_handlers[size_t(opcode) - size_t(IR::Opcode::A32SetCheckBit)])(ctx, &inst);
|
||||
finish_this_inst:
|
||||
ctx.reg_alloc.EndOfAllocScope();
|
||||
#ifndef NDEBUG
|
||||
if (conf.very_verbose_debugging_output)
|
||||
EmitVerboseDebuggingOutput(reg_alloc);
|
||||
@@ -146,15 +172,14 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
||||
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
if (conf.enable_cycle_counting) {
|
||||
if (conf.enable_cycle_counting)
|
||||
EmitAddCycles(block.CycleCount());
|
||||
}
|
||||
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]);
|
||||
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.int3();
|
||||
|
||||
for (auto& deferred_emit : ctx.deferred_emits) {
|
||||
for (auto& deferred_emit : ctx.deferred_emits)
|
||||
deferred_emit();
|
||||
}
|
||||
code.int3();
|
||||
|
||||
const size_t size = size_t(code.getCurr() - entrypoint);
|
||||
@@ -167,6 +192,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
||||
|
||||
auto const bdesc = RegisterBlock(descriptor, entrypoint, size);
|
||||
code.DisableWriting();
|
||||
shared_labels.clear();
|
||||
return bdesc;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -29,7 +29,7 @@ namespace Dynarmic::Backend::X64 {
|
||||
class RegAlloc;
|
||||
|
||||
struct A32EmitContext final : public EmitContext {
|
||||
A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block);
|
||||
A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels);
|
||||
|
||||
A32::LocationDescriptor Location() const;
|
||||
A32::LocationDescriptor EndLocation() const;
|
||||
@@ -130,6 +130,7 @@ public:
|
||||
ankerl::unordered_dense::map<std::tuple<bool, size_t, int, int>, void (*)()> write_fallbacks;
|
||||
ankerl::unordered_dense::map<std::tuple<bool, size_t, int, int>, void (*)()> exclusive_write_fallbacks;
|
||||
ankerl::unordered_dense::set<DoNotFastmemMarker> do_not_fastmem;
|
||||
boost::container::stable_vector<Xbyak::Label> shared_labels;
|
||||
void (*memory_read_128)() = nullptr; // Dummy
|
||||
void (*memory_write_128)() = nullptr; // Dummy
|
||||
const void* terminal_handler_pop_rsb_hint;
|
||||
|
||||
@@ -37,8 +37,10 @@ namespace Dynarmic::Backend::X64 {
|
||||
|
||||
using namespace Xbyak::util;
|
||||
|
||||
A64EmitContext::A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block)
|
||||
: EmitContext(reg_alloc, block), conf(conf) {}
|
||||
A64EmitContext::A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels)
|
||||
: EmitContext(reg_alloc, block, shared_labels)
|
||||
, conf(conf)
|
||||
{}
|
||||
|
||||
A64::LocationDescriptor A64EmitContext::Location() const {
|
||||
return A64::LocationDescriptor{block.Location()};
|
||||
@@ -83,11 +85,14 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept {
|
||||
gprs.reset(size_t(HostLoc::R14));
|
||||
return gprs;
|
||||
}(), any_xmm};
|
||||
A64EmitContext ctx{conf, reg_alloc, block};
|
||||
|
||||
A64EmitContext ctx{conf, reg_alloc, block, shared_labels};
|
||||
|
||||
// Start emitting.
|
||||
code.align();
|
||||
const auto* const entrypoint = code.getCurr();
|
||||
code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp);
|
||||
code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]);
|
||||
|
||||
DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL);
|
||||
typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst);
|
||||
@@ -139,16 +144,13 @@ finish_this_inst:
|
||||
}
|
||||
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
if (conf.enable_cycle_counting) {
|
||||
if (conf.enable_cycle_counting)
|
||||
EmitAddCycles(block.CycleCount());
|
||||
}
|
||||
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]);
|
||||
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.int3();
|
||||
|
||||
for (auto& deferred_emit : ctx.deferred_emits) {
|
||||
for (auto& deferred_emit : ctx.deferred_emits)
|
||||
deferred_emit();
|
||||
}
|
||||
code.int3();
|
||||
|
||||
const size_t size = size_t(code.getCurr() - entrypoint);
|
||||
@@ -161,6 +163,7 @@ finish_this_inst:
|
||||
|
||||
auto bdesc = RegisterBlock(descriptor, entrypoint, size);
|
||||
code.DisableWriting();
|
||||
shared_labels.clear();
|
||||
return bdesc;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
struct A64EmitContext final : public EmitContext {
|
||||
A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block);
|
||||
A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels);
|
||||
|
||||
A64::LocationDescriptor Location() const;
|
||||
bool IsSingleStep() const;
|
||||
@@ -126,6 +126,7 @@ public:
|
||||
ankerl::unordered_dense::map<std::tuple<bool, size_t, int, int>, void (*)()> write_fallbacks;
|
||||
ankerl::unordered_dense::map<std::tuple<bool, size_t, int, int>, void (*)()> exclusive_write_fallbacks;
|
||||
ankerl::unordered_dense::set<DoNotFastmemMarker> do_not_fastmem;
|
||||
boost::container::stable_vector<Xbyak::Label> shared_labels;
|
||||
const void* terminal_handler_pop_rsb_hint = nullptr;
|
||||
const void* terminal_handler_fast_dispatch_hint = nullptr;
|
||||
FastDispatchEntry& (*fast_dispatch_table_lookup)(u64) = nullptr;
|
||||
|
||||
@@ -32,8 +32,11 @@ namespace Dynarmic::Backend::X64 {
|
||||
|
||||
using namespace Xbyak::util;
|
||||
|
||||
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block)
|
||||
: reg_alloc(reg_alloc), block(block) {}
|
||||
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels)
|
||||
: reg_alloc(reg_alloc)
|
||||
, block(block)
|
||||
, shared_labels(shared_labels)
|
||||
{}
|
||||
|
||||
EmitContext::~EmitContext() = default;
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "dynarmic/mcl/bit.hpp"
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <boost/container/stable_vector.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include "dynarmic/mcl/bit.hpp"
|
||||
#include "dynarmic/backend/exception_handler.h"
|
||||
#include "dynarmic/backend/x64/reg_alloc.h"
|
||||
#include "dynarmic/common/fp/fpcr.h"
|
||||
@@ -52,24 +53,23 @@ using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>
|
||||
template<typename T>
|
||||
using HalfVectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T> / 2>;
|
||||
|
||||
using SharedLabel = Xbyak::Label*;
|
||||
struct EmitContext {
|
||||
EmitContext(RegAlloc& reg_alloc, IR::Block& block);
|
||||
EmitContext(RegAlloc& reg_alloc, IR::Block& block, boost::container::stable_vector<Xbyak::Label>& shared_labels);
|
||||
virtual ~EmitContext();
|
||||
virtual FP::FPCR FPCR(bool fpcr_controlled = true) const = 0;
|
||||
virtual bool HasOptimization(OptimizationFlag flag) const = 0;
|
||||
|
||||
RegAlloc& reg_alloc;
|
||||
IR::Block& block;
|
||||
[[nodiscard]] inline Xbyak::Label* GenSharedLabel() noexcept {
|
||||
return &shared_labels.emplace_back();
|
||||
}
|
||||
|
||||
std::vector<std::function<void()>> deferred_emits;
|
||||
RegAlloc& reg_alloc;
|
||||
IR::Block& block;
|
||||
boost::container::stable_vector<Xbyak::Label>& shared_labels;
|
||||
};
|
||||
|
||||
using SharedLabel = std::shared_ptr<Xbyak::Label>;
|
||||
|
||||
inline SharedLabel GenSharedLabel() {
|
||||
return std::make_shared<Xbyak::Label>();
|
||||
}
|
||||
|
||||
class EmitX64 {
|
||||
public:
|
||||
struct BlockDescriptor {
|
||||
|
||||
@@ -136,7 +136,7 @@ void ForceToDefaultNaN(BlockOfCode& code, Xbyak::Xmm result) {
|
||||
|
||||
template<size_t fsize>
|
||||
SharedLabel ProcessNaN(BlockOfCode& code, EmitContext& ctx, Xbyak::Xmm a) {
|
||||
SharedLabel nan = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel nan = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
FCODE(ucomis)(a, a);
|
||||
code.jp(*nan, code.T_NEAR);
|
||||
@@ -251,7 +251,7 @@ template<size_t fsize, typename Function>
|
||||
void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
SharedLabel end = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel();
|
||||
|
||||
Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
||||
|
||||
@@ -304,7 +304,7 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||
const Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr(code);
|
||||
|
||||
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), nan = ctx.GenSharedLabel();
|
||||
|
||||
code.movaps(result, op1);
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
@@ -413,7 +413,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, bo
|
||||
|
||||
DenormalsAreZero<fsize>(code, ctx, {result, operand});
|
||||
|
||||
SharedLabel equal = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel equal = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
FCODE(ucomis)(result, operand);
|
||||
code.jz(*equal, code.T_NEAR);
|
||||
@@ -484,7 +484,7 @@ static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::
|
||||
}
|
||||
};
|
||||
|
||||
SharedLabel end = GenSharedLabel(), z = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), z = ctx.GenSharedLabel();
|
||||
|
||||
FCODE(ucomis)(op1, op2);
|
||||
code.jz(*z, code.T_NEAR);
|
||||
@@ -632,7 +632,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, bo
|
||||
}
|
||||
|
||||
if (code.HasHostFeature(HostFeature::FMA | HostFeature::AVX)) {
|
||||
SharedLabel fallback = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel fallback = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(code, args[0]);
|
||||
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(code, args[1]);
|
||||
@@ -843,7 +843,7 @@ static void EmitFPMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||
const Xbyak::Reg64 tmp = do_default_nan ? INVALID_REG : ctx.reg_alloc.ScratchGpr(code);
|
||||
|
||||
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), nan = ctx.GenSharedLabel();
|
||||
|
||||
if (code.HasHostFeature(HostFeature::AVX)) {
|
||||
FCODE(vmuls)(result, op1, op2);
|
||||
@@ -981,7 +981,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
|
||||
}
|
||||
|
||||
if (code.HasHostFeature(HostFeature::FMA)) {
|
||||
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), fallback = ctx.GenSharedLabel();
|
||||
|
||||
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(code, args[0]);
|
||||
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(code, args[1]);
|
||||
@@ -1129,7 +1129,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
|
||||
const Xbyak::Xmm value = ctx.reg_alloc.ScratchXmm(code);
|
||||
[[maybe_unused]] const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr(code).cvt32();
|
||||
|
||||
SharedLabel bad_values = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel bad_values = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
code.movaps(value, operand);
|
||||
|
||||
@@ -1296,7 +1296,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
|
||||
}
|
||||
|
||||
if (code.HasHostFeature(HostFeature::FMA | HostFeature::AVX)) {
|
||||
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), fallback = ctx.GenSharedLabel();
|
||||
|
||||
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(code, args[0]);
|
||||
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(code, args[1]);
|
||||
@@ -1641,7 +1641,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Xmm scratch = ctx.reg_alloc.ScratchXmm(code);
|
||||
|
||||
if (!unsigned_) {
|
||||
SharedLabel saturate_max = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel saturate_max = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
ZeroIfNaN<64>(code, src, scratch);
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
||||
|
||||
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
if (fastmem_marker) {
|
||||
// Use fastmem
|
||||
@@ -108,7 +108,7 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
conf.recompile_on_fastmem_failure,
|
||||
});
|
||||
|
||||
EmitCheckMemoryAbort(ctx, inst, end.get());
|
||||
EmitCheckMemoryAbort(ctx, inst, end);
|
||||
code.jmp(*end, code.T_NEAR);
|
||||
});
|
||||
} else {
|
||||
@@ -120,7 +120,7 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
||||
code.L(*abort);
|
||||
code.call(wrapped_fn);
|
||||
EmitCheckMemoryAbort(ctx, inst, end.get());
|
||||
EmitCheckMemoryAbort(ctx, inst, end);
|
||||
code.jmp(*end, code.T_NEAR);
|
||||
});
|
||||
}
|
||||
@@ -173,7 +173,7 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
||||
|
||||
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
if (fastmem_marker) {
|
||||
// Use fastmem
|
||||
@@ -195,7 +195,7 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
conf.recompile_on_fastmem_failure,
|
||||
});
|
||||
|
||||
EmitCheckMemoryAbort(ctx, inst, end.get());
|
||||
EmitCheckMemoryAbort(ctx, inst, end);
|
||||
code.jmp(*end, code.T_NEAR);
|
||||
});
|
||||
} else {
|
||||
@@ -207,7 +207,7 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
||||
code.L(*abort);
|
||||
code.call(wrapped_fn);
|
||||
EmitCheckMemoryAbort(ctx, inst, end.get());
|
||||
EmitCheckMemoryAbort(ctx, inst, end);
|
||||
code.jmp(*end, code.T_NEAR);
|
||||
});
|
||||
}
|
||||
@@ -352,7 +352,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
|
||||
|
||||
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
||||
if (fastmem_marker) {
|
||||
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
bool require_abort_handling = false;
|
||||
|
||||
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
|
||||
@@ -427,7 +427,7 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
|
||||
|
||||
EmitExclusiveLock(code, conf, tmp, tmp2.cvt32());
|
||||
|
||||
SharedLabel end = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel();
|
||||
|
||||
code.mov(status, u32(1));
|
||||
code.movzx(tmp.cvt32(), code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)]);
|
||||
@@ -460,7 +460,7 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
|
||||
|
||||
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
||||
if (fastmem_marker) {
|
||||
SharedLabel abort = GenSharedLabel();
|
||||
SharedLabel abort = ctx.GenSharedLabel();
|
||||
bool require_abort_handling = false;
|
||||
|
||||
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling, tmp);
|
||||
|
||||
@@ -54,7 +54,7 @@ void EmitDetectMisalignedVAddr(BlockOfCode& code, EmitContext& ctx, size_t bitsi
|
||||
if (ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) {
|
||||
const u32 page_align_mask = static_cast<u32>(page_table_const_size - 1) & ~align_mask;
|
||||
|
||||
SharedLabel detect_boundary = GenSharedLabel(), resume = GenSharedLabel();
|
||||
SharedLabel detect_boundary = ctx.GenSharedLabel(), resume = ctx.GenSharedLabel();
|
||||
|
||||
code.jnz(*detect_boundary, code.T_NEAR);
|
||||
code.L(*resume);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@
|
||||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/common/fp/info.h"
|
||||
#include "dynarmic/common/fp/op.h"
|
||||
#include "dynarmic/common/fp/rounding_mode.h"
|
||||
#include "dynarmic/common/fp/util.h"
|
||||
#include "dynarmic/interface/optimization_flags.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
@@ -93,7 +94,7 @@ void HandleNaNs(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, std::
|
||||
code.cmp(bitmask, 0);
|
||||
}
|
||||
|
||||
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), nan = ctx.GenSharedLabel();
|
||||
|
||||
code.jnz(*nan, code.T_NEAR);
|
||||
code.L(*end);
|
||||
@@ -188,23 +189,6 @@ void ForceToDefaultNaN(BlockOfCode& code, FP::FPCR fpcr, Xbyak::Xmm result) {
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t fsize>
|
||||
void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm result) {
|
||||
const Xbyak::Xmm nan_mask = xmm0;
|
||||
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
|
||||
constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero,
|
||||
FpFixup::PosZero);
|
||||
FCODE(vfixupimmp)(result, result, code.BConst<32>(ptr_b, nan_to_zero), u8(0));
|
||||
} else if (code.HasHostFeature(HostFeature::AVX)) {
|
||||
FCODE(vcmpordp)(nan_mask, result, result);
|
||||
FCODE(vandp)(result, result, nan_mask);
|
||||
} else {
|
||||
code.movaps(nan_mask, result);
|
||||
FCODE(cmpordp)(nan_mask, nan_mask);
|
||||
code.andps(result, nan_mask);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t fsize>
|
||||
void DenormalsAreZero(BlockOfCode& code, FP::FPCR fpcr, std::initializer_list<Xbyak::Xmm> to_daz, Xbyak::Xmm tmp) {
|
||||
if (fpcr.FZ()) {
|
||||
@@ -1330,7 +1314,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code);
|
||||
|
||||
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), fallback = ctx.GenSharedLabel();
|
||||
|
||||
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
|
||||
code.movaps(result, xmm_a);
|
||||
@@ -1603,7 +1587,7 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
|
||||
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(code, args[1]);
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code);
|
||||
|
||||
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), fallback = ctx.GenSharedLabel();
|
||||
|
||||
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
|
||||
code.movaps(result, GetVectorOf<fsize, false, 0, 2>(code));
|
||||
@@ -1776,7 +1760,7 @@ static void EmitRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* ins
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||
const Xbyak::Xmm value = ctx.reg_alloc.ScratchXmm(code);
|
||||
|
||||
SharedLabel bad_values = GenSharedLabel(), end = GenSharedLabel();
|
||||
SharedLabel bad_values = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||
|
||||
code.movaps(value, operand);
|
||||
|
||||
@@ -1867,7 +1851,7 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code);
|
||||
const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm(code);
|
||||
|
||||
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
|
||||
SharedLabel end = ctx.GenSharedLabel(), fallback = ctx.GenSharedLabel();
|
||||
|
||||
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
|
||||
code.vmovaps(result, GetVectorOf<fsize, false, 0, 3>(code));
|
||||
@@ -2001,161 +1985,216 @@ 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();
|
||||
const auto rounding = static_cast<FP::RoundingMode>(inst->GetArg(2).GetU8());
|
||||
const auto rounding = FP::RoundingMode(inst->GetArg(2).GetU8());
|
||||
[[maybe_unused]] const bool fpcr_controlled = inst->GetArg(3).GetU1();
|
||||
|
||||
if constexpr (fsize != 16) {
|
||||
if (code.HasHostFeature(HostFeature::SSE41) && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
||||
|
||||
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
|
||||
const int round_imm = [&] {
|
||||
switch (rounding) {
|
||||
case FP::RoundingMode::ToNearest_TieEven:
|
||||
default:
|
||||
return 0b00;
|
||||
case FP::RoundingMode::TowardsPlusInfinity:
|
||||
return 0b10;
|
||||
case FP::RoundingMode::TowardsMinusInfinity:
|
||||
return 0b01;
|
||||
case FP::RoundingMode::TowardsZero:
|
||||
return 0b11;
|
||||
}
|
||||
}();
|
||||
|
||||
const auto perform_conversion = [&code, &ctx](const Xbyak::Xmm& src) {
|
||||
// MSVC doesn't allow us to use a [&] capture, so we have to do this instead.
|
||||
(void)ctx;
|
||||
|
||||
if constexpr (fsize == 32) {
|
||||
code.cvttps2dq(src, src);
|
||||
} else {
|
||||
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
|
||||
code.vcvttpd2qq(src, src);
|
||||
} else {
|
||||
const Xbyak::Reg64 hi = ctx.reg_alloc.ScratchGpr(code);
|
||||
const Xbyak::Reg64 lo = ctx.reg_alloc.ScratchGpr(code);
|
||||
|
||||
code.cvttsd2si(lo, src);
|
||||
code.punpckhqdq(src, src);
|
||||
code.cvttsd2si(hi, src);
|
||||
code.movq(src, lo);
|
||||
code.pinsrq(src, hi, 1);
|
||||
|
||||
ctx.reg_alloc.Release(hi);
|
||||
ctx.reg_alloc.Release(lo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (fbits != 0) {
|
||||
const u64 scale_factor = fsize == 32
|
||||
? static_cast<u64>(fbits + 127) << 23
|
||||
: static_cast<u64>(fbits + 1023) << 52;
|
||||
FCODE(mulp)(src, GetVectorOf<fsize>(code, scale_factor));
|
||||
if (code.HasHostFeature(HostFeature::SSE41) && fsize != 16 && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
||||
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
|
||||
const int round_imm = [&] {
|
||||
switch (rounding) {
|
||||
case FP::RoundingMode::ToNearest_TieEven:
|
||||
default:
|
||||
return 0b00;
|
||||
case FP::RoundingMode::TowardsPlusInfinity:
|
||||
return 0b10;
|
||||
case FP::RoundingMode::TowardsMinusInfinity:
|
||||
return 0b01;
|
||||
case FP::RoundingMode::TowardsZero:
|
||||
return 0b11;
|
||||
}
|
||||
}();
|
||||
const auto perform_conversion = [&code, &ctx](const Xbyak::Xmm& src) {
|
||||
// MSVC doesn't allow us to use a [&] capture, so we have to do this instead.
|
||||
(void)ctx;
|
||||
|
||||
FCODE(roundp)(src, src, static_cast<u8>(round_imm));
|
||||
ZeroIfNaN<fsize>(code, src);
|
||||
|
||||
constexpr u64 float_upper_limit_signed = fsize == 32 ? 0x4f000000 : 0x43e0000000000000;
|
||||
[[maybe_unused]] constexpr u64 float_upper_limit_unsigned = fsize == 32 ? 0x4f800000 : 0x43f0000000000000;
|
||||
|
||||
if constexpr (unsigned_) {
|
||||
if constexpr (fsize == 32) {
|
||||
code.cvttps2dq(src, src);
|
||||
} else {
|
||||
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
|
||||
// Mask positive values
|
||||
code.xorps(xmm0, xmm0);
|
||||
FCODE(vcmpp)(k1, src, xmm0, Cmp::GreaterEqual_OQ);
|
||||
|
||||
// Convert positive values to unsigned integers, write 0 anywhere else
|
||||
// vcvttp*2u*q already saturates out-of-range values to (0xFFFF...)
|
||||
if constexpr (fsize == 32) {
|
||||
code.vcvttps2udq(src | k1 | T_z, src);
|
||||
} else {
|
||||
code.vcvttpd2uqq(src | k1 | T_z, src);
|
||||
}
|
||||
code.vcvttpd2qq(src, src);
|
||||
} else {
|
||||
// Zero is minimum
|
||||
code.xorps(xmm0, xmm0);
|
||||
FCODE(cmplep)(xmm0, src);
|
||||
FCODE(andp)(src, xmm0);
|
||||
const Xbyak::Reg64 hi = ctx.reg_alloc.ScratchGpr(code);
|
||||
const Xbyak::Reg64 lo = ctx.reg_alloc.ScratchGpr(code);
|
||||
|
||||
// Will we exceed unsigned range?
|
||||
const Xbyak::Xmm exceed_unsigned = ctx.reg_alloc.ScratchXmm(code);
|
||||
code.movaps(exceed_unsigned, GetVectorOf<fsize, float_upper_limit_unsigned>(code));
|
||||
FCODE(cmplep)(exceed_unsigned, src);
|
||||
code.cvttsd2si(lo, src);
|
||||
code.punpckhqdq(src, src);
|
||||
code.cvttsd2si(hi, src);
|
||||
code.movq(src, lo);
|
||||
code.pinsrq(src, hi, 1);
|
||||
|
||||
// Will be exceed signed range?
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code);
|
||||
code.movaps(tmp, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
||||
code.movaps(xmm0, tmp);
|
||||
FCODE(cmplep)(xmm0, src);
|
||||
FCODE(andp)(tmp, xmm0);
|
||||
FCODE(subp)(src, tmp);
|
||||
perform_conversion(src);
|
||||
ICODE(psll)(xmm0, u8(fsize - 1));
|
||||
FCODE(orp)(src, xmm0);
|
||||
ctx.reg_alloc.Release(hi);
|
||||
ctx.reg_alloc.Release(lo);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (fbits != 0) {
|
||||
const u64 scale_factor = fsize == 32
|
||||
? u64(fbits + 127) << 23
|
||||
: u64(fbits + 1023) << 52;
|
||||
FCODE(mulp)(src, GetVectorOf<fsize>(code, scale_factor));
|
||||
}
|
||||
|
||||
// Saturate to max
|
||||
FCODE(orp)(src, exceed_unsigned);
|
||||
FCODE(roundp)(src, src, u8(round_imm));
|
||||
const Xbyak::Xmm nan_mask = xmm0;
|
||||
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
|
||||
static constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero, FpFixup::PosZero);
|
||||
FCODE(vfixupimmp)(src, src, code.BConst<32>(ptr_b, nan_to_zero), u8(0));
|
||||
} else if (code.HasHostFeature(HostFeature::AVX)) {
|
||||
FCODE(vcmpordp)(nan_mask, src, src);
|
||||
FCODE(vandp)(src, src, nan_mask);
|
||||
} else {
|
||||
code.movaps(nan_mask, src);
|
||||
FCODE(cmpordp)(nan_mask, nan_mask);
|
||||
code.andps(src, nan_mask);
|
||||
}
|
||||
|
||||
constexpr u64 float_upper_limit_signed = fsize == 32 ? 0x4f000000 : 0x43e0000000000000;
|
||||
[[maybe_unused]] constexpr u64 float_upper_limit_unsigned = fsize == 32 ? 0x4f800000 : 0x43f0000000000000;
|
||||
|
||||
if constexpr (unsigned_) {
|
||||
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
|
||||
// Mask positive values
|
||||
code.xorps(xmm0, xmm0);
|
||||
FCODE(vcmpp)(k1, src, xmm0, Cmp::GreaterEqual_OQ);
|
||||
|
||||
// Convert positive values to unsigned integers, write 0 anywhere else
|
||||
// vcvttp*2u*q already saturates out-of-range values to (0xFFFF...)
|
||||
if (fsize == 32) {
|
||||
code.vcvttps2udq(src | k1 | T_z, src);
|
||||
} else {
|
||||
code.vcvttpd2uqq(src | k1 | T_z, src);
|
||||
}
|
||||
} else {
|
||||
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||
constexpr u64 integer_max = FPT((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
|
||||
|
||||
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
||||
// Zero is minimum
|
||||
code.xorps(xmm0, xmm0);
|
||||
FCODE(cmplep)(xmm0, src);
|
||||
FCODE(andp)(src, xmm0);
|
||||
|
||||
// Will we exceed unsigned range?
|
||||
const Xbyak::Xmm exceed_unsigned = ctx.reg_alloc.ScratchXmm(code);
|
||||
code.movaps(exceed_unsigned, GetVectorOf<fsize, float_upper_limit_unsigned>(code));
|
||||
FCODE(cmplep)(exceed_unsigned, src);
|
||||
|
||||
// Will be exceed signed range?
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code);
|
||||
code.movaps(tmp, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
||||
code.movaps(xmm0, tmp);
|
||||
FCODE(cmplep)(xmm0, src);
|
||||
FCODE(andp)(tmp, xmm0);
|
||||
FCODE(subp)(src, tmp);
|
||||
perform_conversion(src);
|
||||
FCODE(blendvp)(src, GetVectorOf<fsize, integer_max>(code));
|
||||
ICODE(psll)(xmm0, u8(fsize - 1));
|
||||
FCODE(orp)(src, xmm0);
|
||||
|
||||
// Saturate to max
|
||||
FCODE(orp)(src, exceed_unsigned);
|
||||
}
|
||||
});
|
||||
|
||||
ctx.reg_alloc.DefineValue(code, inst, src);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||
constexpr u64 integer_max = FPT((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
|
||||
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
||||
FCODE(cmplep)(xmm0, src);
|
||||
perform_conversion(src);
|
||||
FCODE(blendvp)(src, GetVectorOf<fsize, integer_max>(code));
|
||||
}
|
||||
});
|
||||
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) {
|
||||
|
||||
@@ -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.
|
||||
@@ -176,7 +176,7 @@ struct ExceptionHandler::Impl final {
|
||||
|
||||
code.align(16);
|
||||
const u8* exception_handler_without_cb = code.getCurr<u8*>();
|
||||
code.mov(code.eax, static_cast<u32>(ExceptionContinueSearch));
|
||||
code.mov(code.eax, u32(ExceptionContinueSearch));
|
||||
code.ret();
|
||||
|
||||
code.align(16);
|
||||
@@ -192,20 +192,18 @@ struct ExceptionHandler::Impl final {
|
||||
code.lea(code.rsp, code.ptr[code.rsp - 8]);
|
||||
code.mov(code.ABI_PARAM1, std::bit_cast<u64>(&cb));
|
||||
code.mov(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||
code.CallLambda(
|
||||
[](const std::function<FakeCall(u64)>& cb_, PCONTEXT ctx) {
|
||||
FakeCall fc = cb_(ctx->Rip);
|
||||
|
||||
ctx->Rsp -= sizeof(u64);
|
||||
*std::bit_cast<u64*>(ctx->Rsp) = fc.ret_rip;
|
||||
ctx->Rip = fc.call_rip;
|
||||
});
|
||||
code.CallLambda([](const std::function<FakeCall(u64)>& cb_, PCONTEXT ctx) {
|
||||
FakeCall fc = cb_(ctx->Rip);
|
||||
ctx->Rsp -= sizeof(u64);
|
||||
*std::bit_cast<u64*>(ctx->Rsp) = fc.ret_rip;
|
||||
ctx->Rip = fc.call_rip;
|
||||
});
|
||||
code.add(code.rsp, 8);
|
||||
code.mov(code.eax, static_cast<u32>(ExceptionContinueExecution));
|
||||
code.mov(code.eax, u32(ExceptionContinueExecution));
|
||||
code.ret();
|
||||
|
||||
exception_handler_without_cb_offset = static_cast<ULONG>(exception_handler_without_cb - code.getCode<u8*>());
|
||||
exception_handler_with_cb_offset = static_cast<ULONG>(exception_handler_with_cb - code.getCode<u8*>());
|
||||
exception_handler_without_cb_offset = ULONG(exception_handler_without_cb - code.getCode<u8*>());
|
||||
exception_handler_with_cb_offset = ULONG(exception_handler_with_cb - code.getCode<u8*>());
|
||||
|
||||
code.align(16);
|
||||
UNWIND_INFO* unwind_info = static_cast<UNWIND_INFO*>(code.AllocateFromCodeSpace(sizeof(UNWIND_INFO)));
|
||||
|
||||
@@ -417,7 +417,8 @@ HostLoc RegAlloc::SelectARegister(std::bitset<32> desired_locations) const noexc
|
||||
// While R13 and R14 are technically available, we avoid allocating for them
|
||||
// at all costs, because theoretically skipping them is better than spilling
|
||||
// all over the place - i also fixes bugs with high reg pressure
|
||||
} else if (i >= HostLoc::R13 && i <= HostLoc::R15) {
|
||||
// %rbp must not be trashed, so skip it as well
|
||||
} else if (i == HostLoc::RBP || (i >= HostLoc::R13 && i <= HostLoc::R15)) {
|
||||
// skip, do not touch
|
||||
// Intel recommends to reuse registers as soon as they're overwritable (DO NOT SPILL)
|
||||
} else if (loc_info.IsEmpty()) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
@@ -22,14 +22,13 @@ constexpr size_t SpillCount = 64;
|
||||
#endif
|
||||
|
||||
struct alignas(16) StackLayout {
|
||||
// Needs alignment for VMOV and XMM spills
|
||||
alignas(16) std::array<std::array<u64, 2>, SpillCount> spill;
|
||||
s64 cycles_remaining;
|
||||
s64 cycles_to_run;
|
||||
|
||||
std::array<std::array<u64, 2>, SpillCount> spill;
|
||||
|
||||
u32 save_host_MXCSR;
|
||||
|
||||
bool check_bit;
|
||||
u64 abi_base_pointer;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// First we list common shared opcodes
|
||||
// Since we give priority to A64 performance, we include them first, this is so we
|
||||
// can discard all A32 opcodes instead of having a "hole" in our checks
|
||||
@@ -710,6 +713,8 @@ A64OPC(ExclusiveWriteMemory32, U32, U64,
|
||||
A64OPC(ExclusiveWriteMemory64, U32, U64, U64, U64, AccType )
|
||||
A64OPC(ExclusiveWriteMemory128, U32, U64, U64, U128, AccType )
|
||||
|
||||
// Remember to update:
|
||||
// - a32_emit_x64.cpp
|
||||
|
||||
// A32 Context getters/setters
|
||||
A32OPC(SetCheckBit, Void, U1 )
|
||||
|
||||
@@ -415,6 +415,105 @@ TEST_CASE("A64: URSHL", "[a64]") {
|
||||
CHECK(jit.GetVector(9) == Vector{0x0000000000000002, 0x12db8b8280e0ba});
|
||||
}
|
||||
|
||||
TEST_CASE("A64: SQSHLU", "[a64]") {
|
||||
A64TestEnv env;
|
||||
A64::UserConfig jit_user_config{};
|
||||
jit_user_config.callbacks = &env;
|
||||
A64::Jit jit{jit_user_config};
|
||||
|
||||
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
|
||||
code.SQSHLU(V8.B16(), V0.B16(), 1);
|
||||
code.SQSHLU(V9.H8(), V1.H8(), 2);
|
||||
code.SQSHLU(V10.S4(), V2.S4(), 28);
|
||||
code.SQSHLU(V11.D2(), V3.D2(), 4);
|
||||
code.SQSHLU(V12.S4(), V0.S4(), 1);
|
||||
code.SQSHLU(V13.S4(), V1.S4(), 3);
|
||||
code.SQSHLU(V14.S4(), V2.S4(), 0);
|
||||
code.SQSHLU(V15.S4(), V3.S4(), 0);
|
||||
|
||||
jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f});
|
||||
jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff});
|
||||
jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f});
|
||||
jit.SetVector(3, Vector{0xffffffffffffffff, 0x96dc5c140705cd04});
|
||||
|
||||
env.ticks_left = env.code_mem.size();
|
||||
CheckedRun([&]() { jit.Run(); });
|
||||
|
||||
CHECK(jit.GetVector(8) == Vector{0x3000d4d4, 0xfe0000000076009e});
|
||||
CHECK(jit.GetVector(9) == Vector{0x2c0000003c, 0});
|
||||
CHECK(jit.GetVector(10) == Vector{0x10000000'ffffffff, 0xffffffff'ffffffff});
|
||||
CHECK(jit.GetVector(11) == Vector{0, 0});
|
||||
CHECK(jit.GetVector(12) == Vector{0x3174d4d4, 0xfffffffe00000000});
|
||||
CHECK(jit.GetVector(13) == Vector{0x5800000078, 0});
|
||||
CHECK(jit.GetVector(14) == Vector{0x1000000ff, 0x100000007f});
|
||||
CHECK(jit.GetVector(15) == Vector{0, 0x705cd04});
|
||||
}
|
||||
|
||||
TEST_CASE("A64: SMIN", "[a64]") {
|
||||
A64TestEnv env;
|
||||
A64::UserConfig jit_user_config{};
|
||||
jit_user_config.callbacks = &env;
|
||||
A64::Jit jit{jit_user_config};
|
||||
|
||||
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
|
||||
code.SMIN(V8.B16(), V0.B16(), V3.B16());
|
||||
code.SMIN(V9.H8(), V1.H8(), V2.H8());
|
||||
code.SMIN(V10.S4(), V2.S4(), V3.S4());
|
||||
code.SMIN(V11.S4(), V3.S4(), V3.S4());
|
||||
code.SMIN(V12.S4(), V0.S4(), V3.S4());
|
||||
code.SMIN(V13.S4(), V1.S4(), V2.S4());
|
||||
code.SMIN(V14.S4(), V2.S4(), V1.S4());
|
||||
code.SMIN(V15.S4(), V3.S4(), V0.S4());
|
||||
|
||||
jit.SetPC(0);
|
||||
jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f});
|
||||
jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff});
|
||||
jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f});
|
||||
jit.SetVector(3, Vector{0xffffffff'ffffffff, 0x96dc5c14'0705cd04});
|
||||
|
||||
env.ticks_left = 4;
|
||||
CheckedRun([&]() { jit.Run(); });
|
||||
|
||||
REQUIRE(jit.GetVector(8) == Vector{0xffffffffffbaffff, 0x96dcffff94059504});
|
||||
REQUIRE(jit.GetVector(9) == Vector{0x10000000f, 0xffffffffffffffff});
|
||||
REQUIRE(jit.GetVector(10) == Vector{0xffffffffffffffff, 0x96dc5c140000007f});
|
||||
}
|
||||
|
||||
TEST_CASE("A64: SMINP", "[a64]") {
|
||||
A64TestEnv env;
|
||||
A64::UserConfig jit_user_config{};
|
||||
jit_user_config.callbacks = &env;
|
||||
A64::Jit jit{jit_user_config};
|
||||
|
||||
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
|
||||
code.SMINP(V8.B16(), V0.B16(), V3.B16());
|
||||
code.SMINP(V9.H8(), V1.H8(), V2.H8());
|
||||
code.SMINP(V10.S4(), V2.S4(), V1.S4());
|
||||
code.SMINP(V11.S4(), V3.S4(), V3.S4());
|
||||
code.SMINP(V12.S4(), V0.S4(), V3.S4());
|
||||
code.SMINP(V13.S4(), V1.S4(), V2.S4());
|
||||
code.SMINP(V14.S4(), V2.S4(), V1.S4());
|
||||
code.SMINP(V15.S4(), V3.S4(), V0.S4());
|
||||
|
||||
jit.SetPC(0);
|
||||
jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f});
|
||||
jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff});
|
||||
jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f});
|
||||
jit.SetVector(3, Vector{0xffffffff'ffffffff, 0x96dc5c14'0705cd04});
|
||||
|
||||
env.ticks_left = 4;
|
||||
CheckedRun([&]() { jit.Run(); });
|
||||
|
||||
REQUIRE(jit.GetVector(8) == Vector{0xffff9495ffffba6a, 0x961405cdffffffff});
|
||||
REQUIRE(jit.GetVector(9) == Vector{0xffffffff00000000, 0});
|
||||
REQUIRE(jit.GetVector(10) == Vector{0x1000000001, 0xffffffff0000000b});
|
||||
REQUIRE(jit.GetVector(11) == Vector{0x96dc5c14ffffffff, 0x96dc5c14ffffffff});
|
||||
REQUIRE(jit.GetVector(12) == Vector{0x943b954fffffffff, 0x96dc5c14ffffffff});
|
||||
REQUIRE(jit.GetVector(13) == Vector{0xffffffff0000000b, 0x1000000001});
|
||||
REQUIRE(jit.GetVector(14) == Vector{0x1000000001, 0xffffffff0000000b});
|
||||
REQUIRE(jit.GetVector(15) == Vector{0x96dc5c14ffffffff, 0x943b954fffffffff});
|
||||
}
|
||||
|
||||
TEST_CASE("A64: XTN", "[a64]") {
|
||||
A64TestEnv env;
|
||||
A64::UserConfig jit_user_config{};
|
||||
|
||||
@@ -4,22 +4,21 @@
|
||||
#include <random>
|
||||
#include <frozen/string.h>
|
||||
#include "common/settings.h"
|
||||
#include "common/random.h"
|
||||
#include "settings_generator.h"
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
void GenerateSettings() {
|
||||
static std::random_device rd;
|
||||
|
||||
auto gen = Common::Random::GetMT19937();
|
||||
// Web Token
|
||||
if (Settings::values.eden_token.GetValue().empty()) {
|
||||
static constexpr const size_t token_length = 48;
|
||||
static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz";
|
||||
static std::uniform_int_distribution<int> token_dist(0, token_set.size() - 1);
|
||||
std::string result;
|
||||
|
||||
for (size_t i = 0; i < token_length; ++i) {
|
||||
size_t idx = token_dist(rd);
|
||||
size_t idx = token_dist(gen);
|
||||
result += token_set[idx];
|
||||
}
|
||||
Settings::values.eden_token.SetValue(result);
|
||||
@@ -27,8 +26,6 @@ void GenerateSettings() {
|
||||
|
||||
// Randomly generated number because, well, we fill the rest automagically ;)
|
||||
// Other serial parts are filled by Region_Index
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u32> distribution(1, (std::numeric_limits<u32>::max)());
|
||||
if (Settings::values.serial_unit.GetValue() == 0)
|
||||
Settings::values.serial_unit.SetValue(distribution(gen));
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/input.h"
|
||||
#include "hid_core/frontend/input_converter.h"
|
||||
|
||||
@@ -119,15 +123,14 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
|
||||
.properties = properties,
|
||||
};
|
||||
if (TransformToButton(callback).value) {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<s16> distribution(-5000, 5000);
|
||||
status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
|
||||
auto gen = Common::Random::GetMT19937();
|
||||
status.accel.x.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
status.accel.y.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
status.accel.z.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
status.gyro.x.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
status.gyro.y.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
status.gyro.z.raw_value = f32(distribution(gen)) * 0.001f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/random.h"
|
||||
#include "common/settings.h"
|
||||
#include "input_common/drivers/udp_client.h"
|
||||
#include "input_common/helpers/udp_protocol.h"
|
||||
@@ -31,7 +32,7 @@ public:
|
||||
|
||||
explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
|
||||
: callback(std::move(callback_)), timer(io_context),
|
||||
socket(io_context, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {
|
||||
socket(io_context, udp::endpoint(udp::v4(), 0)), client_id(Common::Random::Random32(0)) {
|
||||
boost::system::error_code ec{};
|
||||
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
|
||||
if (ec.value() != boost::system::errc::success) {
|
||||
@@ -64,11 +65,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
u32 GenerateRandomClientId() const {
|
||||
std::random_device device;
|
||||
return device();
|
||||
}
|
||||
|
||||
void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) {
|
||||
if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) {
|
||||
switch (*type) {
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace Network {
|
||||
|
||||
class Room::RoomImpl {
|
||||
public:
|
||||
std::mt19937 random_gen; ///< Random number generator. Used for GenerateFakeIPAddress
|
||||
|
||||
ENetHost* server = nullptr; ///< Network interface.
|
||||
|
||||
std::atomic<State> state{State::Closed}; ///< Current state of the room.
|
||||
@@ -51,7 +49,7 @@ public:
|
||||
IPBanList ip_ban_list; ///< List of banned IP addresses
|
||||
mutable std::mutex ban_list_mutex; ///< Mutex for the ban lists
|
||||
|
||||
RoomImpl() : random_gen(std::random_device()()) {}
|
||||
RoomImpl() {}
|
||||
|
||||
/// Thread that receives and dispatches network packets
|
||||
std::optional<std::jthread> room_thread;
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -49,7 +49,7 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
|
||||
constexpr size_t NUM_STAGES = Maxwell::MaxShaderStage;
|
||||
constexpr size_t MAX_IMAGE_ELEMENTS = 64;
|
||||
constexpr size_t INLINE_IMAGE_ELEMENTS = 64;
|
||||
|
||||
DescriptorLayoutBuilder MakeBuilder(const Device& device, std::span<const Shader::Info> infos) {
|
||||
DescriptorLayoutBuilder builder{device};
|
||||
@@ -264,7 +264,11 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
stage_infos[stage] = *info;
|
||||
enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask;
|
||||
std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
|
||||
num_image_elements += Shader::NumDescriptors(info->texture_buffer_descriptors);
|
||||
num_image_elements += Shader::NumDescriptors(info->image_buffer_descriptors);
|
||||
num_textures += Shader::NumDescriptors(info->texture_descriptors);
|
||||
num_image_elements += Shader::NumDescriptors(info->texture_descriptors);
|
||||
num_image_elements += Shader::NumDescriptors(info->image_descriptors);
|
||||
}
|
||||
fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0];
|
||||
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] {
|
||||
@@ -310,10 +314,10 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
|
||||
|
||||
template <typename Spec>
|
||||
bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views;
|
||||
std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
|
||||
size_t sampler_index{};
|
||||
size_t view_index{};
|
||||
small_vector<VideoCommon::ImageViewInOut, INLINE_IMAGE_ELEMENTS> views;
|
||||
small_vector<VideoCommon::SamplerId, INLINE_IMAGE_ELEMENTS> samplers;
|
||||
views.reserve(num_image_elements);
|
||||
samplers.reserve(num_textures);
|
||||
|
||||
texture_cache.SynchronizeGraphicsDescriptors();
|
||||
|
||||
@@ -358,11 +362,11 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {
|
||||
views.push_back({
|
||||
.index = handle.first,
|
||||
.blacklist = blacklist,
|
||||
.id = {}
|
||||
};
|
||||
});
|
||||
}
|
||||
}};
|
||||
if constexpr (Spec::has_texture_buffers) {
|
||||
@@ -378,10 +382,10 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {handle.first};
|
||||
views.push_back({handle.first});
|
||||
|
||||
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
|
||||
samplers[sampler_index++] = sampler;
|
||||
samplers.push_back(sampler);
|
||||
}
|
||||
}
|
||||
if constexpr (Spec::has_images) {
|
||||
@@ -407,7 +411,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
if constexpr (Spec::enabled_stages[4]) {
|
||||
config_stage(4);
|
||||
}
|
||||
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), view_index));
|
||||
ASSERT(views.size() == num_image_elements);
|
||||
ASSERT(samplers.size() == num_textures);
|
||||
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), views.size()));
|
||||
|
||||
VideoCommon::ImageViewInOut* texture_buffer_it{views.data()};
|
||||
const auto bind_stage_info{[&](size_t stage) LAMBDA_FORCEINLINE {
|
||||
@@ -501,7 +507,8 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
buffer_cache.any_buffer_uploaded = false;
|
||||
}
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
texture_cache.CheckFeedbackLoop(views);
|
||||
texture_cache.CheckFeedbackLoop(std::span<const VideoCommon::ImageViewInOut>{views.data(),
|
||||
views.size()});
|
||||
ConfigureDraw(rescaling, render_area);
|
||||
|
||||
return true;
|
||||
@@ -987,7 +994,7 @@ void GraphicsPipeline::Validate() {
|
||||
num_images += Shader::NumDescriptors(info.texture_descriptors);
|
||||
num_images += Shader::NumDescriptors(info.image_descriptors);
|
||||
}
|
||||
ASSERT(num_images <= MAX_IMAGE_ELEMENTS);
|
||||
ASSERT(num_images == num_image_elements);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -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
|
||||
@@ -159,6 +159,7 @@ private:
|
||||
std::array<Shader::Info, NUM_STAGES> stage_infos;
|
||||
std::array<u32, 5> enabled_uniform_buffer_masks{};
|
||||
VideoCommon::UniformBufferSizes uniform_buffer_sizes{};
|
||||
size_t num_image_elements{};
|
||||
u32 num_textures{};
|
||||
bool fragment_has_color0_output{};
|
||||
|
||||
|
||||
@@ -2733,7 +2733,9 @@ 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);
|
||||
|
||||
+1646
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user