Compare commits
20 commits
87a83717c7
...
23a7bce403
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a7bce403 | ||
|
|
6e141bee23 | ||
|
|
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")
|
||||
|
|
|
|||
283
dist/dev.eden_emu.eden.svg
vendored
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 19 KiB |
BIN
dist/eden.bmp
vendored
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 181 KiB |
BIN
dist/eden.ico
vendored
|
Before Width: | Height: | Size: 335 KiB After Width: | Height: | Size: 317 KiB |
89
dist/icon_variations/aprilfools2026.svg
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
1
dist/icon_variations/aprilfools2026_bgcolor
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
#43fcfcff
|
||||
BIN
dist/qt_themes/default/icons/256x256/eden.png
vendored
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 15 KiB |
9
externals/CMakeLists.txt
vendored
|
|
@ -62,6 +62,12 @@ endif()
|
|||
# unordered_dense
|
||||
AddJsonPackage(unordered-dense)
|
||||
|
||||
# httplib
|
||||
if (IOS)
|
||||
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
|
||||
endif()
|
||||
AddJsonPackage(httplib)
|
||||
|
||||
if (YUZU_STATIC_ROOM)
|
||||
return()
|
||||
endif()
|
||||
|
|
@ -227,9 +233,6 @@ if (VulkanMemoryAllocator_ADDED)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
AddJsonPackage(httplib)
|
||||
|
||||
# cpp-jwt
|
||||
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
|
||||
AddJsonPackage(cpp-jwt)
|
||||
|
|
|
|||
3
externals/cpmfile.json
vendored
|
|
@ -36,7 +36,8 @@
|
|||
"0002-fix-zstd.patch"
|
||||
],
|
||||
"options": [
|
||||
"HTTPLIB_REQUIRE_OPENSSL ON"
|
||||
"HTTPLIB_REQUIRE_OPENSSL ON",
|
||||
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
|
||||
]
|
||||
},
|
||||
"cpp-jwt": {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 44 KiB |
|
|
@ -1 +1 @@
|
|||
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#1F143C</color></resources>
|
||||
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#43fcfcff</color></resources>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -144,7 +146,8 @@ add_library(
|
|||
zstd_compression.cpp
|
||||
zstd_compression.h
|
||||
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
|
||||
fs/symlink.h fs/symlink.cpp)
|
||||
fs/symlink.h fs/symlink.cpp
|
||||
httplib.h)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(common PRIVATE windows/timer_resolution.cpp
|
||||
|
|
@ -242,7 +245,7 @@ else()
|
|||
target_link_libraries(common PUBLIC Boost::headers)
|
||||
endif()
|
||||
|
||||
target_link_libraries(common PUBLIC Boost::filesystem Boost::context)
|
||||
target_link_libraries(common PUBLIC Boost::filesystem Boost::context httplib::httplib)
|
||||
|
||||
if (lz4_ADDED)
|
||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||
|
|
|
|||
18
src/common/httplib.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#ifndef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
#endif
|
||||
#include <httplib.h>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
22
src/common/random.cpp
Normal file
|
|
@ -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()());
|
||||
}
|
||||
}
|
||||
13
src/common/random.h
Normal file
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1269,7 +1269,6 @@ endif()
|
|||
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
|
||||
|
||||
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
|
||||
# TODO
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@
|
|||
#include <fmt/format.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
#include <httplib.h>
|
||||
#endif
|
||||
#include "common/httplib.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
|
@ -103,8 +101,6 @@ std::vector<u8> TryLoadFromDisk(const std::filesystem::path& path) {
|
|||
|
||||
std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem::path& cache_path) {
|
||||
LOG_INFO(Service_BCAT, "Downloading image: https://eden-emu.dev{}", url_path);
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
try {
|
||||
httplib::Client cli("https://eden-emu.dev");
|
||||
cli.set_follow_location(true);
|
||||
|
|
@ -128,8 +124,6 @@ std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem
|
|||
} catch (...) {
|
||||
LOG_WARNING(Service_BCAT, "Failed to download: {}", url_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -232,8 +226,6 @@ void WriteCachedJson(std::string_view json) {
|
|||
}
|
||||
|
||||
std::optional<std::string> DownloadReleasesJson() {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
try {
|
||||
httplib::SSLClient cli{"api.github.com", 443};
|
||||
cli.set_connection_timeout(10);
|
||||
|
|
@ -255,7 +247,6 @@ std::optional<std::string> DownloadReleasesJson() {
|
|||
} catch (...) {
|
||||
LOG_WARNING(Service_BCAT, " failed to download releases");
|
||||
}
|
||||
#endif
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
@ -2004,120 +1988,123 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
|
|||
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);
|
||||
perform_conversion(src);
|
||||
FCODE(blendvp)(src, GetVectorOf<fsize, integer_max>(code));
|
||||
}
|
||||
});
|
||||
FCODE(andp)(src, xmm0);
|
||||
|
||||
ctx.reg_alloc.DefineValue(code, inst, src);
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
ICODE(psll)(xmm0, u8(fsize - 1));
|
||||
FCODE(orp)(src, xmm0);
|
||||
|
||||
// Saturate to max
|
||||
FCODE(orp)(src, exceed_unsigned);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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{};
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ if (ENABLE_UPDATE_CHECKER)
|
|||
target_sources(frontend_common PRIVATE
|
||||
update_checker.cpp
|
||||
update_checker.h)
|
||||
|
||||
target_compile_definitions(frontend_common PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_link_libraries(frontend_common PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include "common/scm_rev.h"
|
||||
#include "update_checker.h"
|
||||
|
||||
#include <httplib.h>
|
||||
#include "common/httplib.h"
|
||||
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
#include <openssl/cert.h>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ if (USE_DISCORD_PRESENCE)
|
|||
|
||||
if (YUZU_USE_BUNDLED_OPENSSL)
|
||||
target_link_libraries(qt_common PUBLIC OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_compile_definitions(qt_common PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(qt_common PUBLIC USE_DISCORD_PRESENCE)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <QEventLoop>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <httplib.h>
|
||||
#include "common/httplib.h"
|
||||
|
||||
#include <discord_rpc.h>
|
||||
#include <fmt/format.h>
|
||||
|
|
|
|||
|
|
@ -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{};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -19,4 +22,3 @@ target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann
|
|||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
|
|
|
|||
|
|
@ -9,17 +9,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#ifndef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
#endif
|
||||
#include <httplib.h>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#include "common/httplib.h"
|
||||
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
#include <openssl/cert.h>
|
||||
|
|
|
|||