Compare commits

..

11 Commits

Author SHA1 Message Date
JPikachu
aa93e0cbb1 [video_core] Bypass mip level assertion to ASSERT_MSG (#2914)
This will bypass the check and continue execution,
preventing crashes in cases where games (like CTGP-DX) may request
more mip levels than supported. This is a temporary solution to bypass
instead of ending the crashing when asserts fail.

Co-authored-by: MaranBr <maranbr@outlook.com>

Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2914
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: JPikachu <jpikachu@eden-emu.dev>
Co-committed-by: JPikachu <jpikachu@eden-emu.dev>
2025-11-01 01:36:03 +01:00
JPikachu
ead5978b34 [kernel] Implement code address offset for Skyline compatibility (#2858)
- Add debug logging for 32-bit syscall argument tracking.

- Add CodeStartOffset constant (0x500000) applied to only 32-bit code address space
  types in KProcess::LoadFromMetadata.

- Replace CheckMemoryStateContiguous with two-stage CheckMemoryState
  in KPageTableBase::UnmapCodeMemory to discover and verify memory
  state more accurately.

Based on similar fixes in Ryujinx (commit 5e9678c8fe)
Fixes compatibility with:
- Skyline 32-bit modding framework
- CTGP-DX (Mario Kart 8 Deluxe mod)
- Other homebrew using 32bit Skyline

Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2858
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu@eden-emu.dev>
Co-committed-by: JPikachu <jpikachu@eden-emu.dev>
2025-10-31 19:49:37 +01:00
lizzie
bfb112dad1 [core/hle/kernel] fix scoped JIT remnants (#2912)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2912
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 19:22:51 +01:00
MaranBr
2d3ba3e5dd [audio_core] Remove unused files and make audio rendering more safe (#2903)
This removes unused files left over in the project and makes audio rendering more safe to avoid any kind of desynchronization or muting.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2903
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-31 18:00:35 +01:00
lizzie
36b736482a [network] Fix potential infinite hang when generating fake IPs (#2898)
ALWAYS bound your loops :)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2898
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 17:38:04 +01:00
lizzie
dbc98f758e [core/memory] Remove defered heap allocation on Linux. (#2587)
Authored-by: weakboson <weakboson@eden-emu.dev>
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2587
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 17:37:21 +01:00
kleidis
84db3351ab [android] Various UX fixups / Improvements (#2870)
- Swap import / export icons on InstallablesFragment and GamePropertiesFragment
- Redesign AddonFragment
- Fix up colors for multiplayer bottom sheets
- Fix up padding in multiplayer lobby browser

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2870
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: kleidis <kleidis1@protonmail.com>
Co-committed-by: kleidis <kleidis1@protonmail.com>
2025-10-31 17:23:15 +01:00
lizzie
3a54d322ab [common] Common::Size -> std::size (#2910)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2910
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 17:22:44 +01:00
lizzie
f9773fa908 [dynarmic] simplify assert macro usage (Only ASSERT/DEBUG_ASSERT are needed) (#2890)
- replace instances of ASSERT() with those where UNREACHABLE() should be used instead
- debuggers exist for a reason, you can't just debug an issue in dynarmic with just printing fancy text... you need to inspect values and alldat - while yes the asserts are "useful"; there is this beautiful thing called backtraces
- this will indirectly speedup the main decoder loop because of the added UNREACHABLE()
- this also removes a bunch of macros that were redundant
- the weird trick of [&](){}() is really funky, just do what everyone has done for the past 30 years and use a `do { <thing> } while(0)` :)

I may or may not have missed one assert or messed up my regex substitutions...

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2890
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 17:22:06 +01:00
lizzie
2dc6d773ee [common, hle/kernel] Remove LTO_NOINLINE (#2908)
- Dont just tell the compiler what to inline/what not to inline; the compiler will be pissed off and make bad codegen
Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2908
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 15:13:31 +01:00
lizzie
402d8e833d [dynarmic/tests] fix dynarmic_test_generator link error (#2906)
Missed the A32 interface impl of Disasemble() in x86_64
Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2906
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-31 13:22:38 +01:00
97 changed files with 724 additions and 1562 deletions

View File

@@ -1,6 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Eden Discord
url: https://discord.gg/kXAmGCXBGD
- name: Eden Revolt
url: https://rvlt.gg/qKgFEAbH
- name: yuzu Discord
url: https://discord.com/invite/u77vRWY
about: If you are experiencing an issue with yuzu, and you need tech support, or if you have a general question, try asking in the official yuzu Discord linked here. Piracy is not allowed.
- name: Community forums
url: https://community.citra-emu.org
about: This is an alternative place for tech support, however helpers there are not as active.

View File

@@ -1,7 +1,6 @@
# Contributing
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
Want to contribute to Eden? That's awesome!
- [Get started by building the emulator](./docs/Build.md)
- [Make an account on the git](./docs/SIGNUP.md)
- [Read the documentation](./docs/README.md)
**The Contributor's Guide has moved to [the yuzu wiki](https://github.com/yuzu-emu/yuzu/wiki/Contributing).**

View File

@@ -82,7 +82,7 @@ Any donations received will go towards things such as:
* Additional hardware (e.g. GPUs as needed to improve rendering support, other peripherals to add support for, etc.)
* CI Infrastructure
If you would prefer to support us in a different way, please join our [Discord](https://discord.gg/kXAmGCXBGD) and talk to Camille or any of our other developers.
If you would prefer to support us in a different way, please join our [Discord](https://discord.gg/edenemu) and talk to Camille or any of our other developers.
## License

View File

@@ -257,7 +257,7 @@ pacman -Syu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt6_devel qt6_5compat_devel libusb1_devel libz_devel glslang mbedtls3
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt6_devel qt6_5compat_devel libusb1_devel libz_devel mbedtls3_devel glslang
```
[Caveats](./Caveats.md#haikuos).

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -20,18 +23,22 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
inner class AddonViewHolder(val binding: ListItemAddonBinding) :
AbstractViewHolder<Patch>(binding) {
override fun bind(model: Patch) {
binding.root.setOnClickListener {
binding.addonCheckbox.isChecked = !binding.addonCheckbox.isChecked
binding.addonCard.setOnClickListener {
binding.addonSwitch.performClick()
}
binding.title.text = model.name
binding.version.text = model.version
binding.addonCheckbox.setOnCheckedChangeListener { _, checked ->
binding.addonSwitch.isChecked = model.enabled
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
model.enabled = checked
}
binding.addonCheckbox.isChecked = model.enabled
binding.buttonDelete.setOnClickListener {
val deleteAction = {
addonViewModel.setAddonToDelete(model)
}
binding.deleteCard.setOnClickListener { deleteAction() }
binding.buttonDelete.setOnClickListener { deleteAction() }
}
}
}

View File

@@ -4,7 +4,8 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
android:padding="16dp"
android:background="?attr/colorSurface">
<TextView
android:id="@+id/text_title"
@@ -13,7 +14,8 @@
android:text="@string/chat"
android:textAppearance="?attr/textAppearanceHeadline6"
android:gravity="center"
android:layout_marginBottom="16dp" />
android:layout_marginBottom="16dp"
android:textColor="?attr/colorOnSurface" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chat_recycler_view"
@@ -39,7 +41,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:imeOptions="actionSend" />
android:imeOptions="actionSend"
android:textColor="?attr/colorOnSurface"
android:textColorHint="?attr/colorOnSurfaceVariant" />
</com.google.android.material.textfield.TextInputLayout>
@@ -50,6 +54,7 @@
android:layout_gravity="bottom"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_send"
android:contentDescription="@string/send_message" />
android:contentDescription="@string/send_message"
app:tint="?attr/colorPrimary" />
</LinearLayout>
</LinearLayout>

View File

@@ -3,13 +3,14 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:background="?attr/colorSurface"
android:elevation="0dp">
<LinearLayout
@@ -37,7 +38,8 @@
android:layout_weight="1"
android:gravity="center"
android:text="@string/multiplayer_room_browser"
android:textAppearance="@style/TextAppearance.Material3.TitleLarge" />
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
android:textColor="?attr/colorOnSurface" />
<FrameLayout
android:layout_width="48dp"
@@ -75,7 +77,8 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="12dp"
app:cardCornerRadius="24dp">
app:cardCornerRadius="24dp"
app:cardBackgroundColor="?attr/colorSurfaceVariant">
<LinearLayout
android:id="@+id/search_container"
@@ -91,6 +94,7 @@
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_search"
android:contentDescription="@string/home_search"
app:tint="?attr/colorOnSurfaceVariant" />
<EditText
@@ -101,7 +105,9 @@
android:hint="@string/multiplayer_search_public_lobbies"
android:imeOptions="flagNoFullscreen"
android:inputType="text"
android:maxLines="1" />
android:maxLines="1"
android:textColor="?attr/colorOnSurface"
android:autofillHints="" />
</LinearLayout>
@@ -113,6 +119,7 @@
android:layout_marginEnd="48dp"
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_clear"
android:contentDescription="@string/clear"
android:visibility="invisible"
app:tint="?attr/colorOnSurfaceVariant"
tools:visibility="visible" />
@@ -154,19 +161,33 @@
android:id="@+id/chip_hide_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:checkable="true"
android:checked="false"
android:text="@string/multiplayer_hide_empty_rooms"
app:chipCornerRadius="16dp" />
app:chipCornerRadius="16dp"
app:chipIconTint="?attr/colorOnSurface"
app:chipIconSize="18dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="6dp"
android:paddingBottom="6dp" />
<com.google.android.material.chip.Chip
android:id="@+id/chip_hide_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:checkable="true"
android:checked="false"
android:text="@string/multiplayer_hide_full_rooms"
app:chipCornerRadius="16dp" />
app:chipCornerRadius="16dp"
app:chipIconTint="?attr/colorOnSurface"
app:chipIconSize="18dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="6dp"
android:paddingBottom="6dp" />
</LinearLayout>
</HorizontalScrollView>
@@ -198,6 +219,7 @@
android:layout_height="72dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_refresh"
android:contentDescription="@string/refresh"
android:alpha="0.5"
app:tint="?attr/colorOnSurface" />
@@ -205,14 +227,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/multiplayer_no_rooms_found"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textColor="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/multiplayer_tap_refresh_to_check_again"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium" />
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.button.MaterialButton
android:id="@+id/empty_refresh_button"
@@ -220,7 +244,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/refresh"
app:icon="@drawable/ic_refresh" />
app:icon="@drawable/ic_refresh"
style="@style/Widget.Material3.Button.ElevatedButton" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@drawable/theme_dialog_background">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
@@ -33,6 +34,7 @@
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:src="@drawable/ic_network"
android:contentDescription="@string/multiplayer"
app:tint="?attr/colorPrimary" />
<LinearLayout
@@ -47,13 +49,18 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_lobby_browser"
style="@style/Widget.Material3.Button.ElevatedButton"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="175dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:layout_marginBottom="16dp"
android:text="@string/multiplayer_public_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_search" />
app:icon="@drawable/ic_search"
app:iconPadding="12dp" />
<Space
android:layout_width="20dp"
@@ -74,12 +81,16 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_join_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_install" />
app:icon="@drawable/ic_install"
app:iconPadding="12dp" />
<Space
android:layout_width="16dp"
android:layout_width="24dp"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
@@ -88,9 +99,13 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_create_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_add" />
app:icon="@drawable/ic_add"
app:iconPadding="12dp" />
</LinearLayout>

View File

@@ -1,7 +1,8 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@drawable/theme_dialog_background">
<LinearLayout
android:orientation="vertical"

View File

@@ -1,6 +1,7 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@drawable/theme_dialog_background">
<LinearLayout
android:orientation="vertical"
@@ -149,6 +150,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/ok"
android:layout_gravity="center" />
android:layout_gravity="center"
style="@style/Widget.Material3.Button.ElevatedButton" />
</LinearLayout>
</ScrollView>

View File

@@ -8,7 +8,7 @@
android:layout_marginBottom="24dp"
android:layout_marginHorizontal="12dp"
android:background="?attr/selectableItemBackground"
android:backgroundTint="?attr/colorSurfaceVariant"
app:cardBackgroundColor="?attr/colorSurfaceVariant"
android:clickable="true"
android:focusable="true">
@@ -46,6 +46,7 @@
android:textAlignment="viewStart"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?attr/colorOnSurface"
tools:text="Room Name" />
<com.google.android.material.textview.MaterialTextView
@@ -56,6 +57,7 @@
android:layout_marginTop="5dp"
android:textAlignment="viewStart"
android:textSize="14sp"
android:textColor="?attr/colorOnSurfaceVariant"
tools:text="Hosted by: Owner" />
<LinearLayout
@@ -70,7 +72,8 @@
android:layout_height="16dp"
android:layout_gravity="center_vertical"
android:contentDescription="@string/multiplayer_game"
android:src="@drawable/ic_controller" />
android:src="@drawable/ic_controller"
app:tint="?attr/colorOnSurfaceVariant" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/game_name"
@@ -81,6 +84,7 @@
android:ellipsize="end"
android:singleLine="true"
android:textStyle="bold"
android:textColor="?attr/colorOnSurface"
tools:text="Game Name" />
</LinearLayout>
</LinearLayout>
@@ -98,7 +102,7 @@
android:layout_height="16dp"
android:src="@drawable/ic_user"
android:contentDescription="@string/multiplayer_player_count"
app:tint="?attr/colorAccent" />
app:tint="?attr/colorPrimary" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/player_count"
@@ -106,7 +110,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="?attr/colorAccent"
android:textColor="?attr/colorPrimary"
tools:text="2/4" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -2,68 +2,109 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/addon_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:focusable="false"
android:paddingHorizontal="20dp"
android:paddingVertical="16dp">
android:padding="8dp">
<LinearLayout
android:id="@+id/text_container"
<com.google.android.material.card.MaterialCardView
android:id="@+id/addon_card"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toStartOf="@+id/addon_checkbox"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.HeadlineMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="17sp"
app:lineHeight="28dp"
tools:text="1440p Resolution" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/version"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:textAlignment="viewStart"
tools:text="1.0.0" />
</LinearLayout>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/addon_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="@+id/text_container"
app:layout_constraintBottom_toBottomOf="@+id/text_container"
app:layout_constraintEnd_toStartOf="@+id/button_delete" />
android:foreground="?attr/selectableItemBackground"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/delete_card"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/button_delete"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/delete"
android:tooltipText="@string/delete"
app:icon="@drawable/ic_delete"
app:iconTint="?attr/colorControlNormal"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="12dp"
android:paddingTop="12dp"
android:paddingBottom="12dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.HeadlineSmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="16sp"
android:ellipsize="end"
android:maxLines="1"
app:lineHeight="20dp"
tools:text="1440p Resolution"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/addon_switch"
android:layout_marginEnd="8dp" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/version"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:textAlignment="viewStart"
android:ellipsize="end"
android:maxLines="1"
tools:text="1.0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintEnd_toStartOf="@+id/addon_switch" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/addon_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="4dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/delete_card"
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
app:cardCornerRadius="10dp"
app:cardElevation="2dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
app:layout_constraintStart_toEndOf="@id/addon_card"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/addon_checkbox"
app:layout_constraintBottom_toBottomOf="@+id/addon_checkbox" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="center">
<ImageButton
android:id="@+id/button_delete"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:background="@null"
android:src="@drawable/ic_delete"
app:tint="@color/eden_border_gradient_end"
android:contentDescription="@string/delete" />
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -200,6 +200,7 @@
<string name="multiplayer_chat">Chat</string>
<string name="multiplayer_more_options">More Options</string>
<string name="chat">Chat</string>
<string name="clear">Clear</string>
<string name="type_message">Type message…</string>
<string name="send_message">Send Message</string>
<string name="multiplayer_moderation">Moderation</string>
@@ -686,7 +687,7 @@
<string name="copy_details">Copy details</string>
<string name="add_ons">Add-ons</string>
<string name="add_ons_description">Toggle mods, updates and DLC</string>
<string name="playtime">Playtime:</string>
<string name="playtime">Playtime: </string>
<string name="reset_playtime">Clear Playtime</string>
<string name="reset_playtime_description">Reset the current game\'s playtime back to 0 seconds</string>
<string name="reset_playtime_warning_description">This will clear the current game\'s playtime data. Are you sure?</string>

View File

@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,19 +28,20 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
constexpr s32 min = (std::numeric_limits<s16>::min)();
constexpr s32 max = (std::numeric_limits<s16>::max)();
auto yuzu_volume = Settings::Volume();
if (yuzu_volume > 1.0f)
yuzu_volume = 0.6f + 20.0f * std::log10(yuzu_volume);
yuzu_volume = std::max(yuzu_volume, 0.001f);
auto const volume = system_volume * device_volume * yuzu_volume;
if (system_channels > device_channels) {
// "Topological" coefficients, basically makes back sounds be less noisy :)
// Front = 1.0; Center = 0.596; LFE = 0.354; Back = 0.707
static constexpr std::array<f32, 4> tcoeff{1.0f, 0.596f, 0.354f, 0.707f};
// We're given 6 channels, but our device only outputs 2, so downmix.
for (u32 r_offs = 0, w_offs = 0; r_offs < samples.size(); r_offs += system_channels, w_offs += device_channels) {
std::array<f32, 6> ccoeff{0.f};
for (u32 i = 0; i < system_channels; ++i)
ccoeff[i] = f32(samples[r_offs + i]);
std::array<f32, 6> rcoeff{
ccoeff[u32(Channels::FrontLeft)],
ccoeff[u32(Channels::BackLeft)],
@@ -48,31 +50,34 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
ccoeff[u32(Channels::BackRight)],
ccoeff[u32(Channels::FrontRight)],
};
std::array<f32, 6> scoeff{
rcoeff[0] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[1] * tcoeff[3],
rcoeff[5] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[4] * tcoeff[3],
rcoeff[4] * tcoeff[0] + rcoeff[3] * tcoeff[1] + rcoeff[2] * tcoeff[2] + rcoeff[2] * tcoeff[3],
rcoeff[3] * tcoeff[0] + rcoeff[3] * tcoeff[1] + rcoeff[2] * tcoeff[2] + rcoeff[3] * tcoeff[3],
rcoeff[2] * tcoeff[0] + rcoeff[4] * tcoeff[1] + rcoeff[1] * tcoeff[2] + rcoeff[0] * tcoeff[3],
rcoeff[1] * tcoeff[0] + rcoeff[4] * tcoeff[1] + rcoeff[1] * tcoeff[2] + rcoeff[5] * tcoeff[3]
};
for (u32 i = 0; i < system_channels; ++i)
samples[w_offs + i] = s16(std::clamp(s32(scoeff[i] * volume), min, max));
const f32 left = rcoeff[0] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[1] * tcoeff[3];
const f32 right = rcoeff[5] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[4] * tcoeff[3];
samples[w_offs + 0] = s16(std::clamp(s32(left * volume), min, max));
samples[w_offs + 1] = s16(std::clamp(s32(right * volume), min, max));
}
queue.EmplaceWait(buffer);
samples_buffer.Push(samples.subspan(0, samples.size() / system_channels * device_channels));
} else if (system_channels < device_channels) {
// We need moar samples! Not all games will provide 6 channel audio.
std::vector<s16> new_samples(samples.size() / system_channels * device_channels);
for (u32 r_offs = 0, w_offs = 0; r_offs < samples.size(); r_offs += system_channels, w_offs += device_channels)
for (u32 channel = 0; channel < system_channels; ++channel)
new_samples[w_offs + channel] = s16(std::clamp(s32(f32(samples[r_offs + channel]) * volume), min, max));
queue.EmplaceWait(buffer);
samples_buffer.Push(new_samples);
} else {
for (u32 i = 0; i < samples.size() && volume != 1.0f; ++i)
samples[i] = s16(std::clamp(s32(f32(samples[i]) * volume), min, max));
if (volume != 1.0f) {
for (u32 i = 0; i < samples.size(); ++i)
samples[i] = s16(std::clamp(s32(f32(samples[i]) * volume), min, max));
}
queue.EmplaceWait(buffer);
samples_buffer.Push(samples);
}
queue.EmplaceWait(buffer);
++queued_buffers;
}
@@ -96,10 +101,12 @@ std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) {
}
void SinkStream::ClearQueue() {
std::scoped_lock lk{release_mutex};
samples_buffer.Pop();
SinkBuffer tmp;
while (queue.TryPop(tmp))
;
while (queue.TryPop(tmp));
queued_buffers = 0;
playing_buffer = {};
playing_buffer.consumed = true;
@@ -122,8 +129,7 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
if (!queue.TryPop(playing_buffer)) {
// If no buffer was available we've underrun, just push the samples and
// continue.
samples_buffer.Push(&input_buffer[frames_written * frame_size],
(num_frames - frames_written) * frame_size);
samples_buffer.Push(&input_buffer[frames_written * frame_size], (num_frames - frames_written) * frame_size);
frames_written = num_frames;
continue;
}
@@ -133,11 +139,9 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
// Get the minimum frames available between the currently playing buffer, and the
// amount we have left to fill
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
num_frames - frames_written)};
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, num_frames - frames_written)};
samples_buffer.Push(&input_buffer[frames_written * frame_size],
frames_available * frame_size);
samples_buffer.Push(&input_buffer[frames_written * frame_size], frames_available * frame_size);
frames_written += frames_available;
playing_buffer.frames_played += frames_available;
@@ -158,63 +162,49 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
size_t frames_written{0};
size_t actual_frames_written{0};
// If we're paused or going to shut down, we don't want to consume buffers as coretiming is
// paused and we'll desync, so just play silence.
if (system.IsPaused() || system.IsShuttingDown()) {
if (system.IsShuttingDown()) {
{
std::scoped_lock lk{release_mutex};
queued_buffers.store(0);
}
std::scoped_lock lk{release_mutex};
queued_buffers.store(0);
release_cv.notify_one();
}
static constexpr std::array<s16, 6> silence{};
for (size_t i = frames_written; i < num_frames; i++)
std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes);
for (size_t i = 0; i < num_frames; i++)
std::memcpy(&output_buffer[i * frame_size], silence.data(), frame_size_bytes);
return;
}
while (frames_written < num_frames) {
// If the playing buffer has been consumed or has no frames, we need a new one
if (playing_buffer.consumed || playing_buffer.frames == 0) {
std::unique_lock lk{release_mutex};
if (!queue.TryPop(playing_buffer)) {
// If no buffer was available we've underrun, fill the remaining buffer with
// the last written frame and continue.
lk.unlock();
for (size_t i = frames_written; i < num_frames; i++)
std::memcpy(&output_buffer[i * frame_size], &last_frame[0], frame_size_bytes);
std::memcpy(&output_buffer[i * frame_size], last_frame.data(), frame_size_bytes);
frames_written = num_frames;
continue;
}
// Successfully dequeued a new buffer.
{
std::unique_lock lk{release_mutex};
queued_buffers--;
}
--queued_buffers;
lk.unlock();
release_cv.notify_one();
}
// Get the minimum frames available between the currently playing buffer, and the
// amount we have left to fill
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
num_frames - frames_written)};
const size_t frames_available = std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, num_frames - frames_written);
samples_buffer.Pop(&output_buffer[frames_written * frame_size],
frames_available * frame_size);
samples_buffer.Pop(&output_buffer[frames_written * frame_size], frames_available * frame_size);
frames_written += frames_available;
actual_frames_written += frames_available;
playing_buffer.frames_played += frames_available;
// If that's all the frames in the current buffer, add its samples and mark it as
// consumed
if (playing_buffer.frames_played >= playing_buffer.frames) {
if (playing_buffer.frames_played >= playing_buffer.frames)
playing_buffer.consumed = true;
}
}
std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size],
frame_size_bytes);
std::memcpy(last_frame.data(), &output_buffer[(frames_written - 1) * frame_size], frame_size_bytes);
{
std::scoped_lock lk{sample_count_lock};
@@ -228,8 +218,7 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
std::scoped_lock lk{sample_count_lock};
auto cur_time{system.CoreTiming().GetGlobalTimeNs()};
auto time_delta{cur_time - last_sample_count_update_time};
auto exp_played_sample_count{min_played_sample_count +
(TargetSampleRate * time_delta) / std::chrono::seconds{1}};
auto exp_played_sample_count{min_played_sample_count + (TargetSampleRate * time_delta) / std::chrono::seconds{1}};
// Add 15ms of latency in sample reporting to allow for some leeway in scheduler timings
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
@@ -238,14 +227,14 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
std::unique_lock lk{release_mutex};
const auto has_space = [this]() {
const u32 current_size = queued_buffers.load(std::memory_order_relaxed);
return paused || max_queue_size == 0 || current_size < max_queue_size;
auto can_continue = [this]() {
return paused || queued_buffers < max_queue_size;
};
if (!has_space()) {
// Wait until the queue falls below the configured limit or the stream is paused/stopped.
release_cv.wait(lk, stop_token, has_space);
release_cv.wait_for(lk, std::chrono::milliseconds(10), can_continue);
if (queued_buffers > max_queue_size + 10) {
release_cv.wait(lk, stop_token, can_continue);
}
}

View File

@@ -15,10 +15,10 @@
#include <vector>
#include "audio_core/common/common.h"
#include "common/bounded_threadsafe_queue.h"
#include "common/common_types.h"
#include "common/polyfill_thread.h"
#include "common/ring_buffer.h"
#include "common/bounded_threadsafe_queue.h"
#include "common/thread.h"
namespace Core {

View File

@@ -28,7 +28,6 @@ add_library(
announce_multiplayer_room.h
assert.cpp
assert.h
atomic_helpers.h
atomic_ops.h
bit_field.h
bit_util.h

View File

@@ -1,776 +0,0 @@
// SPDX-FileCopyrightText: 2013-2016 Cameron Desrochers
// SPDX-FileCopyrightText: 2015 Jeff Preshing
// SPDX-License-Identifier: BSD-2-Clause AND Zlib
// Distributed under the simplified BSD license (see the license file that
// should have come with this header).
// Uses Jeff Preshing's semaphore implementation (under the terms of its
// separate zlib license, embedded below).
#pragma once
// Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant)
// implementation of low-level memory barriers, plus a few semi-portable utility macros (for
// inlining and alignment). Also has a basic atomic type (limited to hardware-supported atomics with
// no memory ordering guarantees). Uses the AE_* prefix for macros (historical reasons), and the
// "moodycamel" namespace for symbols.
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <ctime>
#include <type_traits>
// Platform detection
#if defined(__INTEL_COMPILER)
#define AE_ICC
#elif defined(_MSC_VER)
#define AE_VCPP
#elif defined(__GNUC__)
#define AE_GCC
#endif
#if defined(_M_IA64) || defined(__ia64__)
#define AE_ARCH_IA64
#elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
#define AE_ARCH_X64
#elif defined(_M_IX86) || defined(__i386__)
#define AE_ARCH_X86
#elif defined(_M_PPC) || defined(__powerpc__)
#define AE_ARCH_PPC
#else
#define AE_ARCH_UNKNOWN
#endif
// AE_UNUSED
#define AE_UNUSED(x) ((void)x)
// AE_NO_TSAN/AE_TSAN_ANNOTATE_*
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#if __cplusplus >= 201703L // inline variables require C++17
namespace Common {
inline int ae_tsan_global;
}
#define AE_TSAN_ANNOTATE_RELEASE() \
AnnotateHappensBefore(__FILE__, __LINE__, (void*)(&::moodycamel::ae_tsan_global))
#define AE_TSAN_ANNOTATE_ACQUIRE() \
AnnotateHappensAfter(__FILE__, __LINE__, (void*)(&::moodycamel::ae_tsan_global))
extern "C" void AnnotateHappensBefore(const char*, int, void*);
extern "C" void AnnotateHappensAfter(const char*, int, void*);
#else // when we can't work with tsan, attempt to disable its warnings
#define AE_NO_TSAN __attribute__((no_sanitize("thread")))
#endif
#endif
#endif
#ifndef AE_NO_TSAN
#define AE_NO_TSAN
#endif
#ifndef AE_TSAN_ANNOTATE_RELEASE
#define AE_TSAN_ANNOTATE_RELEASE()
#define AE_TSAN_ANNOTATE_ACQUIRE()
#endif
// AE_FORCEINLINE
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_FORCEINLINE __forceinline
#elif defined(AE_GCC)
// #define AE_FORCEINLINE __attribute__((always_inline))
#define AE_FORCEINLINE inline
#else
#define AE_FORCEINLINE inline
#endif
// AE_ALIGN
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_ALIGN(x) __declspec(align(x))
#elif defined(AE_GCC)
#define AE_ALIGN(x) __attribute__((aligned(x)))
#else
// Assume GCC compliant syntax...
#define AE_ALIGN(x) __attribute__((aligned(x)))
#endif
// Portable atomic fences implemented below:
namespace Common {
enum memory_order {
memory_order_relaxed,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
// memory_order_sync: Forces a full sync:
// #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad
memory_order_sync = memory_order_seq_cst
};
} // namespace Common
#if (defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))) || \
(defined(AE_ICC) && __INTEL_COMPILER < 1600)
// VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences
#include <intrin.h>
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
#define AeFullSync _mm_mfence
#define AeLiteSync _mm_mfence
#elif defined(AE_ARCH_IA64)
#define AeFullSync __mf
#define AeLiteSync __mf
#elif defined(AE_ARCH_PPC)
#include <ppcintrinsics.h>
#define AeFullSync __sync
#define AeLiteSync __lwsync
#endif
#ifdef AE_VCPP
#pragma warning(push)
#pragma warning(disable : 4365) // Disable erroneous 'conversion from long to unsigned int,
// signed/unsigned mismatch' error when using `assert`
#ifdef __cplusplus_cli
#pragma managed(push, off)
#endif
#endif
namespace Common {
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
_ReadBarrier();
break;
case memory_order_release:
_WriteBarrier();
break;
case memory_order_acq_rel:
_ReadWriteBarrier();
break;
case memory_order_seq_cst:
_ReadWriteBarrier();
break;
default:
assert(false);
break;
}
}
// x86/x64 have a strong memory model -- all loads and stores have
// acquire and release semantics automatically (so only need compiler
// barriers for those).
#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
_ReadBarrier();
break;
case memory_order_release:
_WriteBarrier();
break;
case memory_order_acq_rel:
_ReadWriteBarrier();
break;
case memory_order_seq_cst:
_ReadWriteBarrier();
AeFullSync();
_ReadWriteBarrier();
break;
default:
assert(false);
}
}
#else
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
// Non-specialized arch, use heavier memory barriers everywhere just in case :-(
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
_ReadBarrier();
AeLiteSync();
_ReadBarrier();
break;
case memory_order_release:
_WriteBarrier();
AeLiteSync();
_WriteBarrier();
break;
case memory_order_acq_rel:
_ReadWriteBarrier();
AeLiteSync();
_ReadWriteBarrier();
break;
case memory_order_seq_cst:
_ReadWriteBarrier();
AeFullSync();
_ReadWriteBarrier();
break;
default:
assert(false);
}
}
#endif
} // namespace Common
#else
// Use standard library of atomics
#include <atomic>
namespace Common {
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
std::atomic_signal_fence(std::memory_order_acquire);
break;
case memory_order_release:
std::atomic_signal_fence(std::memory_order_release);
break;
case memory_order_acq_rel:
std::atomic_signal_fence(std::memory_order_acq_rel);
break;
case memory_order_seq_cst:
std::atomic_signal_fence(std::memory_order_seq_cst);
break;
default:
assert(false);
}
}
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
AE_TSAN_ANNOTATE_ACQUIRE();
std::atomic_thread_fence(std::memory_order_acquire);
break;
case memory_order_release:
AE_TSAN_ANNOTATE_RELEASE();
std::atomic_thread_fence(std::memory_order_release);
break;
case memory_order_acq_rel:
AE_TSAN_ANNOTATE_ACQUIRE();
AE_TSAN_ANNOTATE_RELEASE();
std::atomic_thread_fence(std::memory_order_acq_rel);
break;
case memory_order_seq_cst:
AE_TSAN_ANNOTATE_ACQUIRE();
AE_TSAN_ANNOTATE_RELEASE();
std::atomic_thread_fence(std::memory_order_seq_cst);
break;
default:
assert(false);
}
}
} // namespace Common
#endif
#if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli))
#define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
#endif
#ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
#include <atomic>
#endif
#include <utility>
// WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY:
// Provides basic support for atomic variables -- no memory ordering guarantees are provided.
// The guarantee of atomicity is only made for types that already have atomic load and store
// guarantees at the hardware level -- on most platforms this generally means aligned pointers and
// integers (only).
namespace Common {
template <typename T>
class weak_atomic {
public:
AE_NO_TSAN weak_atomic() : value() {}
#ifdef AE_VCPP
#pragma warning(push)
#pragma warning(disable : 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
#endif
template <typename U>
AE_NO_TSAN weak_atomic(U&& x) : value(std::forward<U>(x)) {}
#ifdef __cplusplus_cli
// Work around bug with universal reference/nullptr combination that only appears when /clr is
// on
AE_NO_TSAN weak_atomic(nullptr_t) : value(nullptr) {}
#endif
AE_NO_TSAN weak_atomic(weak_atomic const& other) : value(other.load()) {}
AE_NO_TSAN weak_atomic(weak_atomic&& other) : value(std::move(other.load())) {}
#ifdef AE_VCPP
#pragma warning(pop)
#endif
AE_FORCEINLINE operator T() const AE_NO_TSAN {
return load();
}
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
template <typename U>
AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN {
value = std::forward<U>(x);
return *this;
}
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN {
value = other.value;
return *this;
}
AE_FORCEINLINE T load() const AE_NO_TSAN {
return value;
}
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN {
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
if (sizeof(T) == 4)
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
#if defined(_M_AMD64)
else if (sizeof(T) == 8)
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
#endif
#else
#error Unsupported platform
#endif
assert(false && "T must be either a 32 or 64 bit type");
return value;
}
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN {
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
if (sizeof(T) == 4)
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
#if defined(_M_AMD64)
else if (sizeof(T) == 8)
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
#endif
#else
#error Unsupported platform
#endif
assert(false && "T must be either a 32 or 64 bit type");
return value;
}
#else
template <typename U>
AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN {
value.store(std::forward<U>(x), std::memory_order_relaxed);
return *this;
}
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN {
value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed);
return *this;
}
AE_FORCEINLINE T load() const AE_NO_TSAN {
return value.load(std::memory_order_relaxed);
}
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN {
return value.fetch_add(increment, std::memory_order_acquire);
}
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN {
return value.fetch_add(increment, std::memory_order_release);
}
#endif
private:
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
// No std::atomic support, but still need to circumvent compiler optimizations.
// `volatile` will make memory access slow, but is guaranteed to be reliable.
volatile T value;
#else
std::atomic<T> value;
#endif
};
} // namespace Common
// Portable single-producer, single-consumer semaphore below:
#if defined(_WIN32)
// Avoid including windows.h in a header; we only need a handful of
// items, so we'll redeclare them here (this is relatively safe since
// the API generally has to remain stable between Windows versions).
// I know this is an ugly hack but it still beats polluting the global
// namespace with thousands of generic names or adding a .cpp for nothing.
extern "C" {
struct _SECURITY_ATTRIBUTES;
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
long lInitialCount, long lMaximumCount,
const wchar_t* lpName);
__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle,
unsigned long dwMilliseconds);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount,
long* lpPreviousCount);
}
#elif defined(__MACH__)
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#elif defined(FREERTOS)
#include <FreeRTOS.h>
#include <semphr.h>
#include <task.h>
#endif
namespace Common {
// Code in the spsc_sema namespace below is an adaptation of Jeff Preshing's
// portable + lightweight semaphore implementations, originally from
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
// LICENSE:
// Copyright (c) 2015 Jeff Preshing
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
namespace spsc_sema {
#if defined(_WIN32)
class Semaphore {
private:
void* m_hSema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0) : m_hSema() {
assert(initialCount >= 0);
const long maxLong = 0x7fffffff;
m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
assert(m_hSema);
}
AE_NO_TSAN ~Semaphore() {
CloseHandle(m_hSema);
}
bool wait() AE_NO_TSAN {
const unsigned long infinite = 0xffffffff;
return WaitForSingleObject(m_hSema, infinite) == 0;
}
bool try_wait() AE_NO_TSAN {
return WaitForSingleObject(m_hSema, 0) == 0;
}
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;
}
void signal(int count = 1) AE_NO_TSAN {
while (!ReleaseSemaphore(m_hSema, count, nullptr))
;
}
};
#elif defined(__MACH__)
//---------------------------------------------------------
// Semaphore (Apple iOS and OSX)
// Can't use POSIX semaphores due to
// http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
//---------------------------------------------------------
class Semaphore {
private:
semaphore_t m_sema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
assert(initialCount >= 0);
kern_return_t rc =
semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
assert(rc == KERN_SUCCESS);
AE_UNUSED(rc);
}
AE_NO_TSAN ~Semaphore() {
semaphore_destroy(mach_task_self(), m_sema);
}
bool wait() AE_NO_TSAN {
return semaphore_wait(m_sema) == KERN_SUCCESS;
}
bool try_wait() AE_NO_TSAN {
return timed_wait(0);
}
bool timed_wait(std::uint64_t timeout_usecs) AE_NO_TSAN {
mach_timespec_t ts;
ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
ts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000);
// added in OSX 10.10:
// https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
kern_return_t rc = semaphore_timedwait(m_sema, ts);
return rc == KERN_SUCCESS;
}
void signal() AE_NO_TSAN {
while (semaphore_signal(m_sema) != KERN_SUCCESS)
;
}
void signal(int count) AE_NO_TSAN {
while (count-- > 0) {
while (semaphore_signal(m_sema) != KERN_SUCCESS)
;
}
}
};
#elif defined(__unix__)
//---------------------------------------------------------
// Semaphore (POSIX, Linux)
//---------------------------------------------------------
class Semaphore {
private:
sem_t m_sema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
assert(initialCount >= 0);
int rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount));
assert(rc == 0);
AE_UNUSED(rc);
}
AE_NO_TSAN ~Semaphore() {
sem_destroy(&m_sema);
}
bool wait() AE_NO_TSAN {
// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
int rc;
do {
rc = sem_wait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool try_wait() AE_NO_TSAN {
int rc;
do {
rc = sem_trywait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
struct timespec ts;
const int usecs_in_1_sec = 1000000;
const int nsecs_in_1_sec = 1000000000;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += static_cast<time_t>(usecs / usecs_in_1_sec);
ts.tv_nsec += static_cast<long>(usecs % usecs_in_1_sec) * 1000;
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
// so we have to clean things up before passing it in
if (ts.tv_nsec >= nsecs_in_1_sec) {
ts.tv_nsec -= nsecs_in_1_sec;
++ts.tv_sec;
}
int rc;
do {
rc = sem_timedwait(&m_sema, &ts);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
void signal() AE_NO_TSAN {
while (sem_post(&m_sema) == -1)
;
}
void signal(int count) AE_NO_TSAN {
while (count-- > 0) {
while (sem_post(&m_sema) == -1)
;
}
}
};
#elif defined(FREERTOS)
//---------------------------------------------------------
// Semaphore (FreeRTOS)
//---------------------------------------------------------
class Semaphore {
private:
SemaphoreHandle_t m_sema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
assert(initialCount >= 0);
m_sema = xSemaphoreCreateCounting(static_cast<UBaseType_t>(~0ull),
static_cast<UBaseType_t>(initialCount));
assert(m_sema);
}
AE_NO_TSAN ~Semaphore() {
vSemaphoreDelete(m_sema);
}
bool wait() AE_NO_TSAN {
return xSemaphoreTake(m_sema, portMAX_DELAY) == pdTRUE;
}
bool try_wait() AE_NO_TSAN {
// Note: In an ISR context, if this causes a task to unblock,
// the caller won't know about it
if (xPortIsInsideInterrupt())
return xSemaphoreTakeFromISR(m_sema, NULL) == pdTRUE;
return xSemaphoreTake(m_sema, 0) == pdTRUE;
}
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
std::uint64_t msecs = usecs / 1000;
TickType_t ticks = static_cast<TickType_t>(msecs / portTICK_PERIOD_MS);
if (ticks == 0)
return try_wait();
return xSemaphoreTake(m_sema, ticks) == pdTRUE;
}
void signal() AE_NO_TSAN {
// Note: In an ISR context, if this causes a task to unblock,
// the caller won't know about it
BaseType_t rc;
if (xPortIsInsideInterrupt())
rc = xSemaphoreGiveFromISR(m_sema, NULL);
else
rc = xSemaphoreGive(m_sema);
assert(rc == pdTRUE);
AE_UNUSED(rc);
}
void signal(int count) AE_NO_TSAN {
while (count-- > 0)
signal();
}
};
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif
//---------------------------------------------------------
// LightweightSemaphore
//---------------------------------------------------------
class LightweightSemaphore {
public:
typedef std::make_signed<std::size_t>::type ssize_t;
private:
weak_atomic<ssize_t> m_count;
Semaphore m_sema;
bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) AE_NO_TSAN {
ssize_t oldCount;
// Is there a better way to set the initial spin count?
// If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
// as threads start hitting the kernel semaphore.
int spin = 1024;
while (--spin >= 0) {
if (m_count.load() > 0) {
m_count.fetch_add_acquire(-1);
return true;
}
compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop.
}
oldCount = m_count.fetch_add_acquire(-1);
if (oldCount > 0)
return true;
if (timeout_usecs < 0) {
if (m_sema.wait())
return true;
}
if (timeout_usecs > 0 && m_sema.timed_wait(static_cast<uint64_t>(timeout_usecs)))
return true;
// At this point, we've timed out waiting for the semaphore, but the
// count is still decremented indicating we may still be waiting on
// it. So we have to re-adjust the count, but only if the semaphore
// wasn't signaled enough times for us too since then. If it was, we
// need to release the semaphore too.
while (true) {
oldCount = m_count.fetch_add_release(1);
if (oldCount < 0)
return false; // successfully restored things to the way they were
// Oh, the producer thread just signaled the semaphore after all. Try again:
oldCount = m_count.fetch_add_acquire(-1);
if (oldCount > 0 && m_sema.try_wait())
return true;
}
}
public:
AE_NO_TSAN LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount), m_sema() {
assert(initialCount >= 0);
}
bool tryWait() AE_NO_TSAN {
if (m_count.load() > 0) {
m_count.fetch_add_acquire(-1);
return true;
}
return false;
}
bool wait() AE_NO_TSAN {
return tryWait() || waitWithPartialSpinning();
}
bool wait(std::int64_t timeout_usecs) AE_NO_TSAN {
return tryWait() || waitWithPartialSpinning(timeout_usecs);
}
void signal(ssize_t count = 1) AE_NO_TSAN {
assert(count >= 0);
ssize_t oldCount = m_count.fetch_add_release(count);
assert(oldCount >= -1);
if (oldCount < 0) {
m_sema.signal(1);
}
}
std::size_t availableApprox() const AE_NO_TSAN {
ssize_t count = m_count.load();
return count > 0 ? static_cast<std::size_t>(count) : 0;
}
};
} // namespace spsc_sema
} // namespace Common
#if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))
#pragma warning(pop)
#ifdef __cplusplus_cli
#pragma managed(pop)
#endif
#endif

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -39,12 +42,8 @@
#define Crash() exit(1)
#endif
#define LTO_NOINLINE __attribute__((noinline))
#else // _MSC_VER
#define LTO_NOINLINE
// Locale Cross-Compatibility
#define locale_t _locale_t
@@ -129,19 +128,4 @@ namespace Common {
u64(g) << 48 | u64(h) << 56;
}
// std::size() does not support zero-size C arrays. We're fixing that.
template <class C>
constexpr auto Size(const C& c) -> decltype(c.size()) {
return std::size(c);
}
template <class C>
constexpr std::size_t Size(const C& c) {
if constexpr (sizeof(C) == 0) {
return 0;
} else {
return std::size(c);
}
}
} // namespace Common

View File

@@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 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
#include <fstream>
#include <vector>
#include "common/heap_tracker.h"
#include "common/logging/log.h"
#include "common/assert.h"
@@ -36,6 +37,8 @@ HeapTracker::~HeapTracker() = default;
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perm, bool is_separate_heap) {
bool rebuild_required = false;
// When mapping other memory, map pages immediately.
if (!is_separate_heap) {
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
@@ -57,11 +60,29 @@ void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
// Insert into mappings.
m_map_count++;
m_mappings.insert(*map);
const auto it = m_mappings.insert(*map);
// Update tick before possible rebuild.
it->tick = m_tick++;
// Check if we need to rebuild.
if (m_resident_map_count >= m_max_resident_map_count) {
rebuild_required = true;
}
// Map the area.
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
// This map is now resident.
it->is_resident = true;
m_resident_map_count++;
m_resident_mappings.insert(*it);
}
// Finally, map.
this->DeferredMapSeparateHeap(virtual_offset);
if (rebuild_required) {
// A rebuild was required, so perform it now.
this->RebuildSeparateHeapAddressSpace();
}
}
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
@@ -148,6 +169,7 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
// Clamp to end.
next = (std::min)(next, end);
// Reprotect, if we need to.
if (should_protect) {
m_buffer.Protect(cur, next - cur, perm);
@@ -158,51 +180,6 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
}
}
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
if (m_buffer.IsInVirtualRange(fault_address)) {
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
}
return false;
}
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
bool rebuild_required = false;
{
std::scoped_lock lk{m_lock};
// Check to ensure this was a non-resident separate heap mapping.
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
if (it == m_mappings.end() || it->is_resident) {
return false;
}
// Update tick before possible rebuild.
it->tick = m_tick++;
// Check if we need to rebuild.
if (m_resident_map_count > m_max_resident_map_count) {
rebuild_required = true;
}
// Map the area.
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
// This map is now resident.
it->is_resident = true;
m_resident_map_count++;
m_resident_mappings.insert(*it);
}
if (rebuild_required) {
// A rebuild was required, so perform it now.
this->RebuildSeparateHeapAddressSpace();
}
return true;
}
void HeapTracker::RebuildSeparateHeapAddressSpace() {
std::scoped_lock lk{m_rebuild_lock, m_lock};
@@ -213,8 +190,8 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
// Despite being worse in theory, this has proven to be better in practice than more
// regularly dumping a smaller amount, because it significantly reduces average case
// lock contention.
std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
std::size_t const evict_count = m_resident_map_count - desired_count;
const size_t desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
const size_t evict_count = m_resident_map_count - desired_count;
auto it = m_resident_mappings.begin();
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {

View File

@@ -1231,7 +1231,6 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp
arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h

View File

@@ -1,49 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef __linux__
#include "common/signal_chain.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
namespace Core {
namespace {
thread_local Core::Memory::Memory* g_current_memory{};
std::once_flag g_registered{};
struct sigaction g_old_segv {};
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
return;
}
return g_old_segv.sa_sigaction(sig, info, ctx);
}
} // namespace
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
g_current_memory = std::addressof(process->GetMemory());
}
ScopedJitExecution::~ScopedJitExecution() {
g_current_memory = nullptr;
}
void ScopedJitExecution::RegisterHandler() {
std::call_once(g_registered, [] {
struct sigaction sa {};
sa.sa_sigaction = &HandleSigSegv;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
});
}
} // namespace Core
#endif

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -26,24 +29,4 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
return static_cast<HaltReason>(hr);
}
#ifdef __linux__
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process);
~ScopedJitExecution();
static void RegisterHandler();
};
#else
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process) {}
~ScopedJitExecution() {}
static void RegisterHandler() {}
};
#endif
} // namespace Core

View File

@@ -341,15 +341,11 @@ bool ArmDynarmic32::IsInThumbMode() const {
}
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run());
}
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step());
}
@@ -391,7 +387,6 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
m_jit = MakeJit(&page_table_impl);
ScopedJitExecution::RegisterHandler();
}
ArmDynarmic32::~ArmDynarmic32() = default;

View File

@@ -372,15 +372,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
}
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run());
}
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step());
}
@@ -420,7 +416,6 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc
auto& page_table = process->GetPageTable().GetBasePageTable();
auto& page_table_impl = page_table.GetImpl();
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
ScopedJitExecution::RegisterHandler();
}
ArmDynarmic64::~ArmDynarmic64() = default;

View File

@@ -60,15 +60,15 @@ constexpr bool IsInvalidCharacterImpl(char c) {
} // namespace impl
constexpr bool IsInvalidCharacter(char c) {
return impl::IsInvalidCharacterImpl<InvalidCharacters, Common::Size(InvalidCharacters)>(c);
return impl::IsInvalidCharacterImpl<InvalidCharacters, std::size(InvalidCharacters)>(c);
}
constexpr bool IsInvalidCharacterForHostName(char c) {
return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName,
Common::Size(InvalidCharactersForHostName)>(c);
std::size(InvalidCharactersForHostName)>(c);
}
constexpr bool IsInvalidCharacterForMountName(char c) {
return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName,
Common::Size(InvalidCharactersForMountName)>(c);
std::size(InvalidCharactersForMountName)>(c);
}
} // namespace StringTraits

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -25,6 +28,9 @@ namespace Kernel {
namespace {
// TODO: Remove this workaround when proper ASLR is implemented for all address spaces.
constexpr u64 CodeStartOffset = 0x500000UL;
Result TerminateChildren(KernelCore& kernel, KProcess* process,
const KThread* thread_to_not_terminate) {
// Request that all children threads terminate.
@@ -1195,11 +1201,11 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
break;
case FileSys::ProgramAddressSpaceType::Is32Bit:
flag |= Svc::CreateProcessFlag::AddressSpace32Bit;
code_address = 0x20'0000;
code_address = 0x20'0000 + CodeStartOffset;
break;
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
flag |= Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias;
code_address = 0x20'0000;
code_address = 0x20'0000 + CodeStartOffset;
break;
}
@@ -1266,13 +1272,8 @@ void KProcess::InitializeInterfaces() {
#ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) {
// Register the scoped JIT handler before creating any NCE instances
// so that its signal handler will appear first in the signal chain.
Core::ScopedJitExecution::RegisterHandler();
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++)
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
}
} else
#endif
if (this->Is64Bit()) {

View File

@@ -359,7 +359,7 @@ struct KernelCore::Impl {
static inline thread_local u8 host_thread_id = UINT8_MAX;
/// Sets the host thread ID for the caller.
LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
u32 SetHostThreadId(std::size_t core_id) {
// This should only be called during core init.
ASSERT(host_thread_id == UINT8_MAX);
@@ -370,17 +370,16 @@ struct KernelCore::Impl {
}
/// Gets the host thread ID for the caller
LTO_NOINLINE u32 GetHostThreadId() const {
u32 GetHostThreadId() const {
return host_thread_id;
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
const auto initialize{[](KThread* thread) LTO_NOINLINE {
KThread* GetHostDummyThread(KThread* existing_thread) {
const auto initialize{[](KThread* thread) {
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
return thread;
}};
thread_local KThread raw_thread{system.Kernel()};
thread_local KThread* thread = existing_thread ? existing_thread : initialize(&raw_thread);
return thread;
@@ -410,11 +409,11 @@ struct KernelCore::Impl {
static inline thread_local bool is_phantom_mode_for_singlecore{false};
LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
bool IsPhantomModeForSingleCore() const {
return is_phantom_mode_for_singlecore;
}
LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
void SetIsPhantomModeForSingleCore(bool value) {
ASSERT(!is_multicore);
is_phantom_mode_for_singlecore = value;
}
@@ -425,14 +424,14 @@ struct KernelCore::Impl {
static inline thread_local KThread* current_thread{nullptr};
LTO_NOINLINE KThread* GetCurrentEmuThread() {
KThread* GetCurrentEmuThread() {
if (!current_thread) {
current_thread = GetHostDummyThread(nullptr);
}
return current_thread;
}
LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
void SetCurrentEmuThread(KThread* thread) {
current_thread = thread;
}

View File

@@ -1828,6 +1828,10 @@ static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system, std
uint64_t size{};
MemoryPermission perm{};
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x}",
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5));
process_handle = Convert<Handle>(GetArg32(args, 0));
std::array<uint32_t, 2> address_gather{};
address_gather[0] = GetArg32(args, 2);
@@ -1915,6 +1919,10 @@ static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system, std::span
uint64_t src_address{};
uint64_t size{};
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x} [6]={:#x}",
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5), GetArg32(args, 6));
process_handle = Convert<Handle>(GetArg32(args, 0));
std::array<uint32_t, 2> dst_address_gather{};
dst_address_gather[0] = GetArg32(args, 2);
@@ -1942,6 +1950,10 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::sp
uint64_t src_address{};
uint64_t size{};
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x} [6]={:#x}",
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5), GetArg32(args, 6));
process_handle = Convert<Handle>(GetArg32(args, 0));
std::array<uint32_t, 2> dst_address_gather{};
dst_address_gather[0] = GetArg32(args, 2);
@@ -1956,6 +1968,9 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::sp
size_gather[1] = GetArg32(args, 6);
size = Convert<uint64_t>(size_gather);
LOG_DEBUG(Kernel_SVC, "Reconstructed, handle={:#x} dst={:#x} src={:#x} size={:#x}",
process_handle, dst_address, src_address, size);
ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
SetArg32(args, 0, Convert<uint32_t>(ret));

View File

@@ -1230,22 +1230,7 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
if (rasterizer) {
impl->InvalidateGPUMemory(ptr, size);
}
#ifdef __linux__
if (!rasterizer && mapped) {
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
}
#endif
return mapped && ptr != nullptr;
}
bool Memory::InvalidateSeparateHeap(void* fault_address) {
#ifdef __linux__
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
#else
return false;
#endif
}
} // namespace Core::Memory

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -492,8 +495,6 @@ public:
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
bool InvalidateSeparateHeap(void* fault_address);
private:
Core::System& system;

View File

@@ -61,11 +61,7 @@ constexpr RegisterList ToRegList(oaknut::Reg reg) {
if (reg.is_vector()) {
return RegisterList{1} << (reg.index() + 32);
}
if (reg.index() == 31) {
ASSERT_FALSE("ZR not allowed in reg list");
}
ASSERT(reg.index() != 31 && "ZR not allowed in reg list");
if (reg.index() == -1) {
return RegisterList{1} << 31;
}

View File

@@ -28,7 +28,7 @@ AddressSpace::AddressSpace(size_t code_cache_size)
, mem(code_cache_size)
, code(mem.ptr(), mem.ptr())
, fastmem_manager(exception_handler) {
ASSERT_MSG(code_cache_size <= 128 * 1024 * 1024, "code_cache_size > 128 MiB not currently supported");
ASSERT(code_cache_size <= 128 * 1024 * 1024 && "code_cache_size > 128 MiB not currently supported");
exception_handler.Register(mem, code_cache_size);
exception_handler.SetFastmemCallback([this](u64 host_pc) {
@@ -258,7 +258,7 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
c.BL(prelude_info.get_ticks_remaining);
break;
default:
ASSERT_FALSE("Invalid relocation target");
UNREACHABLE();
}
}
@@ -292,7 +292,7 @@ void AddressSpace::LinkBlockLinks(const CodePtr entry_point, const CodePtr targe
}
break;
default:
ASSERT_FALSE("Invalid BlockRelocationType");
UNREACHABLE();
}
}
}
@@ -342,9 +342,9 @@ FakeCall AddressSpace::FastmemCallback(u64 host_pc) {
}
fail:
fmt::print("dynarmic: Segfault happened within JITted code at host_pc = {:016x}\n", host_pc);
fmt::print("Segfault wasn't at a fastmem patch location!\n");
ASSERT_FALSE("segfault");
fmt::print("dynarmic: Segfault happened within JITted code at host_pc = {:016x}\n"
"Segfault wasn't at a fastmem patch location!\n", host_pc);
UNREACHABLE();
}
} // namespace Dynarmic::Backend::Arm64

View File

@@ -112,8 +112,7 @@ void EmitIR<IR::Opcode::GetNZCVFromOp>(oaknut::CodeGenerator& code, EmitContext&
break;
}
default:
ASSERT_FALSE("Invalid type for GetNZCVFromOp");
break;
UNREACHABLE();
}
}
@@ -143,8 +142,7 @@ void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& c
break;
}
default:
ASSERT_FALSE("Invalid type for GetNZFromOp");
break;
UNREACHABLE();
}
}
@@ -241,8 +239,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
#undef A32OPC
#undef A64OPC
default:
ASSERT_FALSE("Invalid opcode: {:x}", std::size_t(inst->GetOpcode()));
break;
UNREACHABLE();
}
reg_alloc.UpdateAllUses();

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -34,7 +37,7 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
ASSERT_FALSE("Interpret should never be emitted.");
UNREACHABLE();
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -20,7 +23,8 @@ namespace Dynarmic::Backend::Arm64 {
using namespace oaknut::util;
static void EmitCoprocessorException() {
ASSERT_FALSE("Should raise coproc exception here");
// TODO: Raise coproc except
UNREACHABLE();
}
static void CallCoprocCallback(oaknut::CodeGenerator& code, EmitContext& ctx, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {

View File

@@ -36,7 +36,7 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
ASSERT_FALSE("Interpret should never be emitted.");
UNREACHABLE();
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -117,7 +120,7 @@ void EmitIR<IR::Opcode::SM4AccessSubstitutionBox>(oaknut::CodeGenerator& code, E
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -123,11 +126,10 @@ static void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*
code.FCVTAS(Rto, Vfrom);
break;
case FP::RoundingMode::ToOdd:
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
break;
UNREACHABLE();
}
} else {
switch (rounding_mode) {
@@ -147,11 +149,10 @@ static void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*
code.FCVTAU(Rto, Vfrom);
break;
case FP::RoundingMode::ToOdd:
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
break;
UNREACHABLE();
}
}
}
@@ -188,7 +189,7 @@ void EmitIR<IR::Opcode::FPAbs16>(oaknut::CodeGenerator& code, EmitContext& ctx,
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -315,7 +316,7 @@ void EmitIR<IR::Opcode::FPMulAdd16>(oaknut::CodeGenerator& code, EmitContext& ct
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -333,7 +334,7 @@ void EmitIR<IR::Opcode::FPMulSub16>(oaknut::CodeGenerator& code, EmitContext& ct
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -361,7 +362,7 @@ void EmitIR<IR::Opcode::FPNeg16>(oaknut::CodeGenerator& code, EmitContext& ctx,
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -379,7 +380,7 @@ void EmitIR<IR::Opcode::FPRecipEstimate16>(oaknut::CodeGenerator& code, EmitCont
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -397,7 +398,7 @@ void EmitIR<IR::Opcode::FPRecipExponent16>(oaknut::CodeGenerator& code, EmitCont
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -415,7 +416,7 @@ void EmitIR<IR::Opcode::FPRecipStepFused16>(oaknut::CodeGenerator& code, EmitCon
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -433,7 +434,7 @@ void EmitIR<IR::Opcode::FPRoundInt16>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -467,9 +468,8 @@ void EmitIR<IR::Opcode::FPRoundInt32>(oaknut::CodeGenerator& code, EmitContext&
case FP::RoundingMode::ToNearest_TieAwayFromZero:
code.FRINTA(Sresult, Soperand);
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
}
UNREACHABLE();
}
}
@@ -505,7 +505,7 @@ void EmitIR<IR::Opcode::FPRoundInt64>(oaknut::CodeGenerator& code, EmitContext&
code.FRINTA(Dresult, Doperand);
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
UNREACHABLE();
}
}
}
@@ -515,7 +515,7 @@ void EmitIR<IR::Opcode::FPRSqrtEstimate16>(oaknut::CodeGenerator& code, EmitCont
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -533,7 +533,7 @@ void EmitIR<IR::Opcode::FPRSqrtStepFused16>(oaknut::CodeGenerator& code, EmitCon
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -647,7 +647,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS16>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -655,7 +655,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS32>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -663,7 +663,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS64>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -671,7 +671,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU16>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -679,7 +679,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU32>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -687,7 +687,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU64>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>

View File

@@ -315,7 +315,7 @@ CodePtr EmitMemoryLdr(oaknut::CodeGenerator& code, int value_idx, oaknut::XReg X
code.DMB(oaknut::BarrierOp::ISH);
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
} else {
fastmem_location = code.xptr<CodePtr>();
@@ -337,7 +337,7 @@ CodePtr EmitMemoryLdr(oaknut::CodeGenerator& code, int value_idx, oaknut::XReg X
code.LDR(oaknut::QReg{value_idx}, Xbase, Roffset, index_ext);
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
}
@@ -376,7 +376,7 @@ CodePtr EmitMemoryStr(oaknut::CodeGenerator& code, int value_idx, oaknut::XReg X
code.DMB(oaknut::BarrierOp::ISH);
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
} else {
fastmem_location = code.xptr<CodePtr>();
@@ -398,7 +398,7 @@ CodePtr EmitMemoryStr(oaknut::CodeGenerator& code, int value_idx, oaknut::XReg X
code.STR(oaknut::QReg{value_idx}, Xbase, Roffset, index_ext);
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -131,7 +134,7 @@ void EmitIR<IR::Opcode::SignedSaturatedAdd8>(oaknut::CodeGenerator& code, EmitCo
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -139,7 +142,7 @@ void EmitIR<IR::Opcode::SignedSaturatedAdd16>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -147,7 +150,7 @@ void EmitIR<IR::Opcode::SignedSaturatedAdd32>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -155,7 +158,7 @@ void EmitIR<IR::Opcode::SignedSaturatedAdd64>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -163,7 +166,7 @@ void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh16>(oaknut::Cod
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -171,7 +174,7 @@ void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh32>(oaknut::Cod
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -179,7 +182,7 @@ void EmitIR<IR::Opcode::SignedSaturatedSub8>(oaknut::CodeGenerator& code, EmitCo
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -187,7 +190,7 @@ void EmitIR<IR::Opcode::SignedSaturatedSub16>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -195,7 +198,7 @@ void EmitIR<IR::Opcode::SignedSaturatedSub32>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -203,7 +206,7 @@ void EmitIR<IR::Opcode::SignedSaturatedSub64>(oaknut::CodeGenerator& code, EmitC
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -211,7 +214,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedAdd8>(oaknut::CodeGenerator& code, Emit
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -219,7 +222,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedAdd16>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -227,7 +230,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedAdd32>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -235,7 +238,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedAdd64>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -243,7 +246,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedSub8>(oaknut::CodeGenerator& code, Emit
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -251,7 +254,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedSub16>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -259,7 +262,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedSub32>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -267,7 +270,7 @@ void EmitIR<IR::Opcode::UnsignedSaturatedSub64>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
} // namespace Dynarmic::Backend::Arm64

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -638,7 +641,7 @@ void EmitIR<IR::Opcode::VectorEqual128>(oaknut::CodeGenerator& code, EmitContext
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -867,7 +870,7 @@ void EmitIR<IR::Opcode::VectorMaxS64>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -890,7 +893,7 @@ void EmitIR<IR::Opcode::VectorMaxU64>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -913,7 +916,7 @@ void EmitIR<IR::Opcode::VectorMinS64>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -936,7 +939,7 @@ void EmitIR<IR::Opcode::VectorMinU64>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -956,7 +959,7 @@ void EmitIR<IR::Opcode::VectorMultiply32>(oaknut::CodeGenerator& code, EmitConte
template<>
void EmitIR<IR::Opcode::VectorMultiply64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
ASSERT_MSG(ctx.conf.very_verbose_debugging_output, "VectorMultiply64 is for debugging only");
ASSERT(ctx.conf.very_verbose_debugging_output && "VectorMultiply64 is for debugging only");
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
code.FMOV(Xscratch0, Qa->toD());
code.FMOV(Xscratch1, Qb->toD());
@@ -1383,7 +1386,7 @@ void EmitIR<IR::Opcode::VectorSignExtend64>(oaknut::CodeGenerator& code, EmitCon
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -1406,7 +1409,7 @@ void EmitIR<IR::Opcode::VectorSignedMultiply16>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -1414,7 +1417,7 @@ void EmitIR<IR::Opcode::VectorSignedMultiply32>(oaknut::CodeGenerator& code, Emi
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -1600,7 +1603,7 @@ void EmitIR<IR::Opcode::VectorSub64>(oaknut::CodeGenerator& code, EmitContext& c
template<>
void EmitIR<IR::Opcode::VectorTable>(oaknut::CodeGenerator&, EmitContext&, IR::Inst* inst) {
// Do nothing. We *want* to hold on to the refcount for our arguments, so VectorTableLookup can use our arguments.
ASSERT_MSG(inst->UseCount() == 1, "Table cannot be used multiple times");
ASSERT(inst->UseCount() == 1 && "Table cannot be used multiple times");
}
template<>
@@ -1665,9 +1668,8 @@ void EmitIR<IR::Opcode::VectorTableLookup64>(oaknut::CodeGenerator& code, EmitCo
code.TBX(Dresult->B8(), oaknut::List{V0.B16(), V1.B16()}, Dindices->B8());
}
break;
default:
ASSERT_FALSE("Unsupported table_size");
}
UNREACHABLE();
}
template<>
@@ -1729,9 +1731,8 @@ void EmitIR<IR::Opcode::VectorTableLookup128>(oaknut::CodeGenerator& code, EmitC
code.TBX(Qresult->B16(), oaknut::List{V0.B16(), V1.B16(), V2.B16(), V3.B16()}, Qindices->B16());
}
break;
default:
ASSERT_FALSE("Unsupported table_size");
}
UNREACHABLE();
}
template<>
@@ -1778,7 +1779,7 @@ void EmitIR<IR::Opcode::VectorUnsignedMultiply16>(oaknut::CodeGenerator& code, E
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -1786,7 +1787,7 @@ void EmitIR<IR::Opcode::VectorUnsignedMultiply32>(oaknut::CodeGenerator& code, E
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>

View File

@@ -227,11 +227,10 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst)
code.FCVTAS(Vto, Vfrom);
break;
case FP::RoundingMode::ToOdd:
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
break;
UNREACHABLE();
}
} else {
switch (rounding_mode) {
@@ -251,11 +250,10 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst)
code.FCVTAU(Vto, Vfrom);
break;
case FP::RoundingMode::ToOdd:
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
break;
UNREACHABLE();
}
}
}
@@ -340,7 +338,7 @@ void EmitIR<IR::Opcode::FPVectorEqual16>(oaknut::CodeGenerator& code, EmitContex
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -465,7 +463,7 @@ void EmitIR<IR::Opcode::FPVectorMulAdd16>(oaknut::CodeGenerator& code, EmitConte
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -493,7 +491,7 @@ void EmitIR<IR::Opcode::FPVectorNeg16>(oaknut::CodeGenerator& code, EmitContext&
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -538,7 +536,7 @@ void EmitIR<IR::Opcode::FPVectorRecipEstimate16>(oaknut::CodeGenerator& code, Em
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -556,7 +554,7 @@ void EmitIR<IR::Opcode::FPVectorRecipStepFused16>(oaknut::CodeGenerator& code, E
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -647,9 +645,8 @@ void EmitIR<IR::Opcode::FPVectorRoundInt32>(oaknut::CodeGenerator& code, EmitCon
case FP::RoundingMode::ToNearest_TieAwayFromZero:
code.FRINTA(Qresult->S4(), Qoperand->S4());
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
}
UNREACHABLE();
}
});
}
@@ -687,9 +684,8 @@ void EmitIR<IR::Opcode::FPVectorRoundInt64>(oaknut::CodeGenerator& code, EmitCon
case FP::RoundingMode::ToNearest_TieAwayFromZero:
code.FRINTA(Qresult->D2(), Qoperand->D2());
break;
default:
ASSERT_FALSE("Invalid RoundingMode");
}
UNREACHABLE();
}
});
}
@@ -699,7 +695,7 @@ void EmitIR<IR::Opcode::FPVectorRSqrtEstimate16>(oaknut::CodeGenerator& code, Em
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -717,7 +713,7 @@ void EmitIR<IR::Opcode::FPVectorRSqrtStepFused16>(oaknut::CodeGenerator& code, E
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -772,7 +768,7 @@ void EmitIR<IR::Opcode::FPVectorToSignedFixed16>(oaknut::CodeGenerator& code, Em
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>
@@ -790,7 +786,7 @@ void EmitIR<IR::Opcode::FPVectorToUnsignedFixed16>(oaknut::CodeGenerator& code,
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
}
template<>

View File

@@ -136,7 +136,7 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
const IR::Value arg = inst->GetArg(i);
ret[i].value = arg;
if (!arg.IsImmediate() && !IsValuelessType(arg.GetType())) {
ASSERT_MSG(ValueLocation(arg.GetInst()), "argument must already been defined");
ASSERT(ValueLocation(arg.GetInst()) && "argument must already been defined");
ValueInfo(arg.GetInst()).uses_this_inst++;
}
}
@@ -328,8 +328,7 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
switch (current_location->kind) {
case HostLoc::Kind::Gpr:
ASSERT_FALSE("Logic error");
break;
UNREACHABLE(); //logic error
case HostLoc::Kind::Fpr:
code.FMOV(oaknut::XReg{new_location_index}, oaknut::DReg{current_location->index});
// ASSERT size fits
@@ -354,13 +353,12 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
code.FMOV(oaknut::DReg{new_location_index}, oaknut::XReg{current_location->index});
break;
case HostLoc::Kind::Fpr:
ASSERT_FALSE("Logic error");
break;
UNREACHABLE(); //logic error
case HostLoc::Kind::Spill:
code.LDR(oaknut::QReg{new_location_index}, SP, spill_offset + current_location->index * spill_slot_size);
break;
case HostLoc::Kind::Flags:
ASSERT_FALSE("Moving from flags into fprs is not currently supported");
ASSERT(false && "Moving from flags into fprs is not currently supported");
break;
}
@@ -368,7 +366,7 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
fprs[new_location_index].realized = true;
return new_location_index;
} else if constexpr (required_kind == HostLoc::Kind::Flags) {
ASSERT_FALSE("A simple read from flags is likely a logic error.");
UNREACHABLE(); //A simple read from flags is likely a logic error
} else {
static_assert(Common::always_false_v<mcl::mp::lift_value<required_kind>>);
}
@@ -414,7 +412,7 @@ int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst*
LoadCopyInto(read_value, oaknut::QReg{write_loc});
return write_loc;
} else if constexpr (kind == HostLoc::Kind::Flags) {
ASSERT_FALSE("Incorrect function for ReadWrite of flags");
ASSERT(false && "Incorrect function for ReadWrite of flags");
} else {
static_assert(Common::always_false_v<mcl::mp::lift_value<kind>>);
}
@@ -486,7 +484,7 @@ void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) {
code.LDR(Wscratch0, SP, spill_offset + current_location->index * spill_slot_size);
code.MSR(oaknut::SystemReg::NZCV, Xscratch0);
} else {
ASSERT_FALSE("Invalid current location for flags");
UNREACHABLE(); //ASSERT(false && "Invalid current location for flags");
}
if (write) {
@@ -508,7 +506,7 @@ void RegAlloc::SpillFlags() {
int RegAlloc::FindFreeSpill() const {
const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); });
ASSERT_MSG(iter != spills.end(), "All spill locations are full");
ASSERT(iter != spills.end() && "All spill locations are full");
return static_cast<int>(iter - spills.begin());
}
@@ -558,8 +556,7 @@ void RegAlloc::LoadCopyInto(const IR::Value& value, oaknut::QReg reg) {
code.LDR(reg, SP, spill_offset + current_location->index * spill_slot_size);
break;
case HostLoc::Kind::Flags:
ASSERT_FALSE("Moving from flags into fprs is not currently supported");
break;
UNREACHABLE(); //ASSERT(false && "Moving from flags into fprs is not currently supported");
}
}
@@ -592,7 +589,7 @@ HostLocInfo& RegAlloc::ValueInfo(HostLoc host_loc) {
case HostLoc::Kind::Spill:
return spills[static_cast<size_t>(host_loc.index)];
}
ASSERT_FALSE("RegAlloc::ValueInfo: Invalid HostLoc::Kind");
UNREACHABLE();
}
HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) {
@@ -600,17 +597,14 @@ HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) {
if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) {
return *iter;
}
if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) {
} else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) {
return *iter;
}
if (contains_value(flags)) {
} else if (contains_value(flags)) {
return flags;
}
if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) {
} else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) {
return *iter;
}
ASSERT_FALSE("RegAlloc::ValueInfo: Value not found");
UNREACHABLE();
}
} // namespace Dynarmic::Backend::Arm64

View File

@@ -182,7 +182,7 @@ public:
} else if constexpr (size == 32) {
return ReadW(arg);
} else {
ASSERT_FALSE("Invalid size to ReadReg {}", size);
UNREACHABLE();
}
}
@@ -199,7 +199,7 @@ public:
} else if constexpr (size == 8) {
return ReadB(arg);
} else {
ASSERT_FALSE("Invalid size to ReadVec {}", size);
UNREACHABLE();
}
}
@@ -221,7 +221,7 @@ public:
} else if constexpr (size == 32) {
return WriteW(inst);
} else {
ASSERT_FALSE("Invalid size to WriteReg {}", size);
UNREACHABLE();
}
}
@@ -238,7 +238,7 @@ public:
} else if constexpr (size == 8) {
return WriteB(inst);
} else {
ASSERT_FALSE("Invalid size to WriteVec {}", size);
UNREACHABLE();
}
}
@@ -258,7 +258,7 @@ public:
} else if constexpr (size == 32) {
return ReadWriteW(arg, inst);
} else {
ASSERT_FALSE("Invalid size to ReadWriteReg {}", size);
UNREACHABLE();
}
}
@@ -275,7 +275,7 @@ public:
} else if constexpr (size == 8) {
return ReadWriteB(arg, inst);
} else {
ASSERT_FALSE("Invalid size to ReadWriteVec {}", size);
UNREACHABLE();
}
}
@@ -371,9 +371,8 @@ void RAReg<T>::Realize() {
case RWType::ReadWrite:
reg = T{reg_alloc.RealizeReadWriteImpl<kind>(read_value, write_value)};
break;
default:
ASSERT_FALSE("Invalid RWType");
}
UNREACHABLE();
}
} // namespace Dynarmic::Backend::Arm64

View File

@@ -88,16 +88,14 @@ private:
};
MachHandler::MachHandler() {
#define KCHECK(x) ASSERT_MSG((x) == KERN_SUCCESS, "dynarmic: macOS MachHandler: init failure at {}", #x)
#define KCHECK(x) ASSERT((x) == KERN_SUCCESS && "init failure at " #x)
KCHECK(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port));
KCHECK(mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND));
KCHECK(task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, server_port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE));
// The below doesn't actually work, and I'm not sure why; since this doesn't work we'll have a spurious error message upon shutdown.
// The below doesn't actually work, and I'm not sure why; since this doesn't work we'll have a spurious
// error message upon shutdown.
mach_port_t prev;
KCHECK(mach_port_request_notification(mach_task_self(), server_port, MACH_NOTIFY_PORT_DESTROYED, 0, server_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev));
#undef KCHECK
thread = std::thread(&MachHandler::MessagePump, this);

View File

@@ -12,6 +12,8 @@
#include <mutex>
#include <shared_mutex>
#include <optional>
#include <bit>
#include <fmt/format.h>
#include <ankerl/unordered_dense.h>
#include "dynarmic/backend/exception_handler.h"
#include "dynarmic/common/assert.h"
@@ -27,7 +29,6 @@
#else
# error "Invalid architecture"
#endif
#include <bit>
namespace Dynarmic::Backend {
@@ -139,7 +140,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
}
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
#elif defined(ARCHITECTURE_riscv64)
ASSERT_FALSE("Unimplemented");
UNREACHABLE();
#else
# error "Invalid architecture"
#endif

View File

@@ -128,7 +128,7 @@ void A32AddressSpace::Link(EmittedBlockInfo& block_info) {
break;
}
default:
ASSERT_FALSE("Invalid relocation target");
UNREACHABLE();
}
}
}

View File

@@ -121,7 +121,7 @@ struct Jit::Impl final {
private:
void RequestCacheInvalidation() {
// ASSERT_FALSE("Unimplemented");
// UNREACHABLE();
invalidate_entire_cache = false;
invalid_cache_ranges.clear();

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2024 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -16,8 +19,7 @@ class CodeBlock {
public:
explicit CodeBlock(std::size_t size) noexcept : memsize(size) {
mem = (u8*)mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
if (mem == nullptr)
ASSERT_FALSE("out of memory");
ASSERT(mem != nullptr);
}
~CodeBlock() noexcept {

View File

@@ -143,8 +143,7 @@ EmittedBlockInfo EmitRV64(biscuit::Assembler& as, IR::Block block, const EmitCon
#undef A32OPC
#undef A64OPC
default:
ASSERT_FALSE("Invalid opcode: {:x}", std::size_t(inst->GetOpcode()));
break;
UNREACHABLE();
}
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2024 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -105,15 +108,14 @@ void EmitA32Cond(biscuit::Assembler& as, EmitContext&, IR::Cond cond, biscuit::L
as.BNEZ(Xscratch0, label);
break;
default:
ASSERT_MSG(false, "Unknown cond {}", static_cast<size_t>(cond));
break;
UNREACHABLE();
}
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(biscuit::Assembler&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
ASSERT_FALSE("Interpret should never be emitted.");
UNREACHABLE();
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {

View File

@@ -105,7 +105,7 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
const IR::Value arg = inst->GetArg(i);
ret[i].value = arg;
if (!arg.IsImmediate() && !IsValuelessType(arg.GetType())) {
ASSERT_MSG(ValueLocation(arg.GetInst()), "argument must already been defined");
ASSERT(ValueLocation(arg.GetInst()) && "argument must already been defined");
ValueInfo(arg.GetInst()).uses_this_inst++;
}
}
@@ -193,8 +193,7 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) {
switch (current_location->kind) {
case HostLoc::Kind::Gpr:
ASSERT_FALSE("Logic error");
break;
UNREACHABLE(); //logic error
case HostLoc::Kind::Fpr:
as.FMV_X_D(biscuit::GPR(new_location_index), biscuit::FPR{current_location->index});
// ASSERT size fits
@@ -216,8 +215,7 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) {
as.FMV_D_X(biscuit::FPR{new_location_index}, biscuit::GPR(current_location->index));
break;
case HostLoc::Kind::Fpr:
ASSERT_FALSE("Logic error");
break;
UNREACHABLE(); //logic error
case HostLoc::Kind::Spill:
as.FLD(biscuit::FPR{new_location_index}, spill_offset + current_location->index * spill_slot_size, biscuit::sp);
break;
@@ -299,7 +297,7 @@ void RegAlloc::SpillFpr(u32 index) {
u32 RegAlloc::FindFreeSpill() const {
const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); });
ASSERT_MSG(iter != spills.end(), "All spill locations are full");
ASSERT(iter != spills.end() && "All spill locations are full");
return static_cast<u32>(iter - spills.begin());
}
@@ -307,14 +305,11 @@ std::optional<HostLoc> RegAlloc::ValueLocation(const IR::Inst* value) const {
const auto contains_value = [value](const HostLocInfo& info) {
return info.Contains(value);
};
if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) {
return HostLoc{HostLoc::Kind::Gpr, static_cast<u32>(iter - gprs.begin())};
}
if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) {
} else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) {
return HostLoc{HostLoc::Kind::Fpr, static_cast<u32>(iter - fprs.begin())};
}
if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) {
} else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) {
return HostLoc{HostLoc::Kind::Spill, static_cast<u32>(iter - spills.begin())};
}
return std::nullopt;
@@ -323,30 +318,27 @@ std::optional<HostLoc> RegAlloc::ValueLocation(const IR::Inst* value) const {
HostLocInfo& RegAlloc::ValueInfo(HostLoc host_loc) {
switch (host_loc.kind) {
case HostLoc::Kind::Gpr:
return gprs[static_cast<size_t>(host_loc.index)];
return gprs[size_t(host_loc.index)];
case HostLoc::Kind::Fpr:
return fprs[static_cast<size_t>(host_loc.index)];
return fprs[size_t(host_loc.index)];
case HostLoc::Kind::Spill:
return spills[static_cast<size_t>(host_loc.index)];
return spills[size_t(host_loc.index)];
}
ASSERT_FALSE("RegAlloc::ValueInfo: Invalid HostLoc::Kind");
UNREACHABLE();
}
HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) {
const auto contains_value = [value](const HostLocInfo& info) {
return info.Contains(value);
};
if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) {
return *iter;
}
if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != gprs.end()) {
} else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != gprs.end()) {
return *iter;
} else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != gprs.end()) {
return *iter;
}
if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != gprs.end()) {
return *iter;
}
ASSERT_FALSE("RegAlloc::ValueInfo: Value not found");
UNREACHABLE();
}
} // namespace Dynarmic::Backend::RV64

View File

@@ -48,18 +48,16 @@ static Xbyak::Address MJitStateReg(A32::Reg reg) {
static Xbyak::Address MJitStateExtReg(A32::ExtReg reg) {
if (A32::IsSingleExtReg(reg)) {
const size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::S0);
const size_t index = size_t(reg) - size_t(A32::ExtReg::S0);
return dword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + sizeof(u32) * index];
}
if (A32::IsDoubleExtReg(reg)) {
const size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::D0);
} else if (A32::IsDoubleExtReg(reg)) {
const size_t index = size_t(reg) - size_t(A32::ExtReg::D0);
return qword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + sizeof(u64) * index];
}
if (A32::IsQuadExtReg(reg)) {
const size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::Q0);
} else if (A32::IsQuadExtReg(reg)) {
const size_t index = size_t(reg) - size_t(A32::ExtReg::Q0);
return xword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + 2 * sizeof(u64) * index];
}
ASSERT_FALSE("Should never happen.");
UNREACHABLE();
}
A32EmitContext::A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, IR::Block& block)
@@ -144,7 +142,8 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
#undef OPCODE
#undef A32OPC
#undef A64OPC
default: [[unlikely]] ASSERT_FALSE("Invalid opcode: {:x}", std::size_t(inst->GetOpcode()));
default:
UNREACHABLE();
}
reg_alloc.EndOfAllocScope();
func(reg_alloc);
@@ -846,7 +845,7 @@ void A32EmitX64::EmitA32SetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
}
static void EmitCoprocessorException() {
ASSERT_FALSE("Should raise coproc exception here");
UNREACHABLE();
}
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
@@ -1126,9 +1125,9 @@ std::string A32EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr
}
void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag(), "Unimplemented");
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag(), "Unimplemented");
ASSERT_MSG(terminal.num_instructions == 1, "Unimplemented");
ASSERT(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag() && "Unimplemented");
ASSERT(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag() && "Unimplemented");
ASSERT(terminal.num_instructions == 1 && "Unimplemented");
code.mov(code.ABI_PARAM2.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
code.mov(code.ABI_PARAM3.cvt32(), 1);

View File

@@ -323,4 +323,8 @@ void Jit::ClearExclusiveState() {
impl->ClearExclusiveState();
}
std::string Jit::Disassemble() const {
return impl->Disassemble();
}
} // namespace Dynarmic::A32

View File

@@ -129,10 +129,8 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept {
#undef OPCODE
#undef A32OPC
#undef A64OPC
default: [[unlikely]] {
ASSERT_MSG(false, "Invalid opcode: {:x}", std::size_t(opcode));
goto finish_this_inst;
}
default:
UNREACHABLE();
}
opcode_branch:
(this->*opcode_handlers[size_t(opcode)])(ctx, &inst);

View File

@@ -507,8 +507,7 @@ void BlockOfCode::LoadRequiredFlagsForCondFromRax(IR::Cond cond) {
case IR::Cond::NV:
break;
default:
ASSERT_MSG(false, "Unknown cond {}", static_cast<size_t>(cond));
break;
UNREACHABLE();
}
}

View File

@@ -59,7 +59,7 @@ std::optional<EmitX64::BlockDescriptor> EmitX64::GetBasicBlock(IR::LocationDescr
}
void EmitX64::EmitInvalid(EmitContext&, IR::Inst* inst) {
ASSERT_MSG(false, "Invalid opcode: {:x}", std::size_t(inst->GetOpcode()));
UNREACHABLE();
}
void EmitX64::EmitVoid(EmitContext&, IR::Inst*) {
@@ -352,7 +352,7 @@ void EmitX64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial
if constexpr (!std::is_same_v<T, IR::Term::Invalid>) {
this->EmitTerminalImpl(x, initial_location, is_single_step);
} else {
ASSERT_MSG(false, "Invalid terminal");
ASSERT(false && "Invalid terminal");
}
}, terminal);
}

View File

@@ -195,7 +195,7 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst*
code.mov(else_, then_);
break;
default:
ASSERT_MSG(false, "Invalid cond {}", static_cast<size_t>(args[0].GetImmediateCond()));
UNREACHABLE();
}
ctx.reg_alloc.DefineValue(inst, else_);

View File

@@ -39,11 +39,10 @@ FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
InvalidateBasicBlocks({std::get<0>(marker)});
}
return result;
} else {
fmt::print("dynarmic: Segfault happened within JITted code at rip = {:016x}\n"
"Segfault wasn't at a fastmem patch location!\n", rip_);
UNREACHABLE(); //("iter != fastmem_patch_info.end()");
}
fmt::print("dynarmic: Segfault happened within JITted code at rip = {:016x}\n"
"Segfault wasn't at a fastmem patch location!\n", rip_);
UNREACHABLE(); //("iter != fastmem_patch_info.end()");
}
template<std::size_t bitsize, auto callback>

View File

@@ -243,7 +243,7 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg
}
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
return fastmem_location;
} else {
@@ -265,7 +265,7 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg
code.movups(Xbyak::Xmm(value_idx), xword[addr]);
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
return fastmem_location;
}
@@ -311,7 +311,7 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int
break;
}
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
return fastmem_location;
} else {
@@ -333,7 +333,7 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int
code.movups(xword[addr], Xbyak::Xmm(value_idx));
break;
default:
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
return fastmem_location;
}

View File

@@ -2425,27 +2425,27 @@ void EmitX64::EmitVectorMultiply64(EmitContext& ctx, IR::Inst* inst) {
}
void EmitX64::EmitVectorMultiplySignedWiden8(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplySignedWiden8");
UNREACHABLE();
}
void EmitX64::EmitVectorMultiplySignedWiden16(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplySignedWiden16");
UNREACHABLE();
}
void EmitX64::EmitVectorMultiplySignedWiden32(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplySignedWiden32");
UNREACHABLE();
}
void EmitX64::EmitVectorMultiplyUnsignedWiden8(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplyUnsignedWiden8");
UNREACHABLE();
}
void EmitX64::EmitVectorMultiplyUnsignedWiden16(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplyUnsignedWiden16");
UNREACHABLE();
}
void EmitX64::EmitVectorMultiplyUnsignedWiden32(EmitContext&, IR::Inst*) {
ASSERT_FALSE("Unexpected VectorMultiplyUnsignedWiden32");
UNREACHABLE();
}
void EmitX64::EmitVectorNarrow16(EmitContext& ctx, IR::Inst* inst) {
@@ -5039,7 +5039,7 @@ void EmitX64::EmitVectorSub64(EmitContext& ctx, IR::Inst* inst) {
void EmitX64::EmitVectorTable(EmitContext&, IR::Inst* inst) {
// Do nothing. We *want* to hold on to the refcount for our arguments, so VectorTableLookup can use our arguments.
ASSERT_MSG(inst->UseCount() == 1, "Table cannot be used multiple times");
ASSERT(inst->UseCount() == 1 && "Table cannot be used multiple times");
}
void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) {

View File

@@ -55,9 +55,6 @@ struct OpArg {
case 64:
inner_reg = inner_reg.cvt64();
return;
default:
ASSERT_MSG(false, "Invalid bits");
return;
}
}
UNREACHABLE();

View File

@@ -40,18 +40,6 @@ static inline bool CanExchange(const HostLoc a, const HostLoc b) noexcept {
// Minimum number of bits required to represent a type
static inline size_t GetBitWidth(const IR::Type type) noexcept {
switch (type) {
case IR::Type::A32Reg:
case IR::Type::A32ExtReg:
case IR::Type::A64Reg:
case IR::Type::A64Vec:
case IR::Type::CoprocInfo:
case IR::Type::Cond:
case IR::Type::Void:
case IR::Type::Table:
case IR::Type::AccType:
ASSERT_FALSE("Type {} cannot be represented at runtime", type);
case IR::Type::Opaque:
ASSERT_FALSE("Not a concrete type");
case IR::Type::U1:
return 8;
case IR::Type::U8:
@@ -66,17 +54,14 @@ static inline size_t GetBitWidth(const IR::Type type) noexcept {
return 128;
case IR::Type::NZCVFlags:
return 32; // TODO: Update to 16 when flags optimization is done
default:
// A32REG A32EXTREG A64REG A64VEC COPROCINFO COND VOID TABLE ACCTYPE OPAQUE
UNREACHABLE();
}
UNREACHABLE();
}
static inline bool IsValuelessType(const IR::Type type) noexcept {
switch (type) {
case IR::Type::Table:
return true;
default:
return false;
}
return type == IR::Type::Table;
}
void HostLocInfo::ReleaseOne() noexcept {
@@ -223,7 +208,7 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(const IR::Inst* inst) noexcept
const auto arg = inst->GetArg(i);
ret[i].value = arg;
if (!arg.IsImmediate() && !IsValuelessType(arg.GetType())) {
ASSERT_MSG(ValueLocation(arg.GetInst()), "argument must already been defined");
ASSERT(ValueLocation(arg.GetInst()) && "argument must already been defined");
LocInfo(*ValueLocation(arg.GetInst())).AddArgReference();
}
}
@@ -467,19 +452,19 @@ HostLoc RegAlloc::SelectARegister(const boost::container::static_vector<HostLoc,
auto const it_final = it_empty_candidate != desired_locations.cend()
? it_empty_candidate : it_candidate != desired_locations.cend()
? it_candidate : it_rex_candidate;
ASSERT_MSG(it_final != desired_locations.cend(), "All candidate registers have already been allocated");
ASSERT(it_final != desired_locations.cend() && "All candidate registers have already been allocated");
// Evil magic - increment LRU counter (will wrap at 256)
const_cast<RegAlloc*>(this)->LocInfo(*it_final).lru_counter++;
return *it_final;
}
void RegAlloc::DefineValueImpl(IR::Inst* def_inst, HostLoc host_loc) noexcept {
ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined");
ASSERT(!ValueLocation(def_inst) && "def_inst has already been defined");
LocInfo(host_loc).AddValue(def_inst);
}
void RegAlloc::DefineValueImpl(IR::Inst* def_inst, const IR::Value& use_inst) noexcept {
ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined");
ASSERT(!ValueLocation(def_inst) && "def_inst has already been defined");
if (use_inst.IsImmediate()) {
const HostLoc location = ScratchImpl(gpr_order);
@@ -488,13 +473,13 @@ void RegAlloc::DefineValueImpl(IR::Inst* def_inst, const IR::Value& use_inst) no
return;
}
ASSERT_MSG(ValueLocation(use_inst.GetInst()), "use_inst must already be defined");
ASSERT(ValueLocation(use_inst.GetInst()) && "use_inst must already be defined");
const HostLoc location = *ValueLocation(use_inst.GetInst());
DefineValueImpl(def_inst, location);
}
HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) noexcept {
ASSERT_MSG(imm.IsImmediate(), "imm is not an immediate");
ASSERT(imm.IsImmediate() && "imm is not an immediate");
if (HostLocIsGPR(host_loc)) {
const Xbyak::Reg64 reg = HostLocToReg64(host_loc);
const u64 imm_value = imm.GetImmediateAsU64();
@@ -521,7 +506,7 @@ void RegAlloc::Move(HostLoc to, HostLoc from) noexcept {
const size_t bit_width = LocInfo(from).GetMaxBitWidth();
ASSERT(LocInfo(to).IsEmpty() && !LocInfo(from).IsLocked());
ASSERT(bit_width <= HostLocBitWidth(to));
ASSERT_MSG(!LocInfo(from).IsEmpty(), "Mov eliminated");
ASSERT(!LocInfo(from).IsEmpty() && "Mov eliminated");
EmitMove(bit_width, to, from);
LocInfo(to) = std::exchange(LocInfo(from), {});
}
@@ -554,9 +539,9 @@ void RegAlloc::MoveOutOfTheWay(HostLoc reg) noexcept {
}
void RegAlloc::SpillRegister(HostLoc loc) noexcept {
ASSERT_MSG(HostLocIsRegister(loc), "Only registers can be spilled");
ASSERT_MSG(!LocInfo(loc).IsEmpty(), "There is no need to spill unoccupied registers");
ASSERT_MSG(!LocInfo(loc).IsLocked(), "Registers that have been allocated must not be spilt");
ASSERT(HostLocIsRegister(loc) && "Only registers can be spilled");
ASSERT(!LocInfo(loc).IsEmpty() && "There is no need to spill unoccupied registers");
ASSERT(!LocInfo(loc).IsLocked() && "Registers that have been allocated must not be spilt");
auto const new_loc = FindFreeSpill(HostLocIsXMM(loc));
Move(new_loc, loc);
}
@@ -582,14 +567,14 @@ HostLoc RegAlloc::FindFreeSpill(bool is_xmm) const noexcept {
for (size_t i = size_t(HostLoc::FirstSpill); i < hostloc_info.size(); ++i)
if (const auto loc = HostLoc(i); LocInfo(loc).IsEmpty())
return loc;
ASSERT_FALSE("All spill locations are full");
UNREACHABLE();
};
void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc from) noexcept {
auto const spill_to_op_arg_helper = [&](HostLoc loc, size_t reserved_stack_space) {
ASSERT(HostLocIsSpill(loc));
size_t i = size_t(loc) - size_t(HostLoc::FirstSpill);
ASSERT_MSG(i < SpillCount, "Spill index greater than number of available spill locations");
ASSERT(i < SpillCount && "Spill index greater than number of available spill locations");
return Xbyak::util::rsp + reserved_stack_space + ABI_SHADOW_SPACE + offsetof(StackLayout, spill) + i * sizeof(StackLayout::spill[0]);
};
auto const spill_xmm_to_op = [&](const HostLoc loc) {
@@ -669,18 +654,13 @@ void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc
code->mov(Xbyak::util::dword[spill_to_op_arg_helper(to, reserved_stack_space)], HostLocToReg64(from).cvt32());
}
} else {
ASSERT_FALSE("Invalid RegAlloc::EmitMove");
UNREACHABLE();
}
}
void RegAlloc::EmitExchange(const HostLoc a, const HostLoc b) noexcept {
if (HostLocIsGPR(a) && HostLocIsGPR(b)) {
code->xchg(HostLocToReg64(a), HostLocToReg64(b));
} else if (HostLocIsXMM(a) && HostLocIsXMM(b)) {
ASSERT_FALSE("Check your code: Exchanging XMM registers is unnecessary");
} else {
ASSERT_FALSE("Invalid RegAlloc::EmitExchange");
}
ASSERT(HostLocIsGPR(a) && HostLocIsGPR(b) && "Exchanging XMM registers is uneeded OR invalid emit");
code->xchg(HostLocToReg64(a), HostLocToReg64(b));
}
} // namespace Dynarmic::Backend::X64

View File

@@ -3,13 +3,11 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fmt/format.h>
#include <cstdio>
#include <exception>
[[noreturn]] void assert_terminate_impl(const char* expr_str, fmt::string_view msg, fmt::format_args args) {
fmt::print(stderr, "assertion failed: {}\n", expr_str);
fmt::vprint(stderr, msg, args);
[[noreturn]] void assert_terminate_impl(const char* s) {
std::puts(s);
std::fflush(stderr);
std::terminate();
}

View File

@@ -6,48 +6,22 @@
#pragma once
#include <fmt/format.h>
[[noreturn]] void assert_terminate_impl(const char* expr_str, fmt::string_view msg, fmt::format_args args);
template<typename... Ts>
[[noreturn]] void assert_terminate(const char* expr_str, fmt::string_view msg, Ts... args) {
assert_terminate_impl(expr_str, msg, fmt::make_format_args(args...));
}
// Temporary until MCL is fully removed
#ifndef ASSERT_MSG
#define ASSERT_MSG(_a_, ...) \
([&]() { \
if (!(_a_)) [[unlikely]] { \
assert_terminate(#_a_, __VA_ARGS__); \
} \
}())
#endif
#ifndef ASSERT_FALSE
#define ASSERT_FALSE(...) \
([&]() { \
assert_terminate("false", __VA_ARGS__); \
}())
#endif
// TODO: Use source_info?
[[noreturn]] void assert_terminate_impl(const char* s);
#ifndef ASSERT
#define ASSERT(_a_) ASSERT_MSG(_a_, "")
# define ASSERT(expr) do if(!(expr)) [[unlikely]] assert_terminate_impl(__FILE__ ": " #expr); while(0)
#endif
#ifndef UNREACHABLE
#define UNREACHABLE() ASSERT_MSG(false, "unreachable")
# ifdef _MSC_VER
# define UNREACHABLE() ASSERT(false && __FILE__ ": unreachable")
# else
# define UNREACHABLE() __builtin_unreachable();
# endif
#endif
#ifdef _DEBUG
#ifndef DEBUG_ASSERT
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
#endif
#ifndef DEBUG_ASSERT_MSG
#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
#endif
#else // not debug
#ifndef DEBUG_ASSERT
#define DEBUG_ASSERT(_a_)
#endif
#ifndef DEBUG_ASSERT_MSG
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
#endif
# ifndef NDEBUG
# define DEBUG_ASSERT(_a_) ASSERT(_a_)
# else
# define DEBUG_ASSERT(_a_)
# endif
#endif

View File

@@ -73,7 +73,7 @@ public:
/// Set rounding mode control field.
void RMode(FP::RoundingMode rounding_mode) {
ASSERT_MSG(static_cast<u32>(rounding_mode) <= 0b11, "FPCR: Invalid rounding mode");
ASSERT(static_cast<u32>(rounding_mode) <= 0b11 && "FPCR: Invalid rounding mode");
value = mcl::bit::set_bits<22, 23>(value, static_cast<u32>(rounding_mode));
}
@@ -93,7 +93,7 @@ public:
/// Set the stride of a vector when executing AArch32 VFP instructions.
/// This field has no function in AArch64 state.
void Stride(size_t stride) {
ASSERT_MSG(stride >= 1 && stride <= 2, "FPCR: Invalid stride");
ASSERT(stride >= 1 && stride <= 2 && "FPCR: Invalid stride");
value = mcl::bit::set_bits<20, 21>(value, stride == 1 ? 0b00u : 0b11u);
}
@@ -116,7 +116,7 @@ public:
/// Sets the length of a vector when executing AArch32 VFP instructions.
/// This field has no function in AArch64 state.
void Len(size_t len) {
ASSERT_MSG(len >= 1 && len <= 8, "FPCR: Invalid len");
ASSERT(len >= 1 && len <= 8 && "FPCR: Invalid len");
value = mcl::bit::set_bits<16, 18>(value, static_cast<u32>(len - 1));
}

View File

@@ -18,44 +18,31 @@ namespace Dynarmic::FP {
void FPProcessException(FPExc exception, FPCR fpcr, FPSR& fpsr) {
switch (exception) {
case FPExc::InvalidOp:
if (fpcr.IOE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.IOE() && "Raising floating point exceptions unimplemented");
fpsr.IOC(true);
break;
case FPExc::DivideByZero:
if (fpcr.DZE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.DZE() && "Raising floating point exceptions unimplemented");
fpsr.DZC(true);
break;
case FPExc::Overflow:
if (fpcr.OFE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.OFE() && "Raising floating point exceptions unimplemented");
fpsr.OFC(true);
break;
case FPExc::Underflow:
if (fpcr.UFE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.UFE() && "Raising floating point exceptions unimplemented");
fpsr.UFC(true);
break;
case FPExc::Inexact:
if (fpcr.IXE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.IXE() && "Raising floating point exceptions unimplemented");
fpsr.IXC(true);
break;
case FPExc::InputDenorm:
if (fpcr.IDE()) {
ASSERT_FALSE("Raising floating point exceptions unimplemented");
}
ASSERT(!fpcr.IDE() && "Raising floating point exceptions unimplemented");
fpsr.IDC(true);
break;
default:
UNREACHABLE();
break;
}
}

View File

@@ -56,15 +56,11 @@ IR::U32 IREmitter::GetRegister(Reg reg) {
}
IR::U32U64 IREmitter::GetExtendedRegister(ExtReg reg) {
if (A32::IsSingleExtReg(reg)) {
if (A32::IsSingleExtReg(reg))
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister32, IR::Value(reg));
}
if (A32::IsDoubleExtReg(reg)) {
else if (A32::IsDoubleExtReg(reg))
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister64, IR::Value(reg));
}
ASSERT_FALSE("Invalid reg.");
UNREACHABLE();
}
IR::U128 IREmitter::GetVector(ExtReg reg) {
@@ -83,7 +79,7 @@ void IREmitter::SetExtendedRegister(const ExtReg reg, const IR::U32U64& value) {
} else if (A32::IsDoubleExtReg(reg)) {
Inst(Opcode::A32SetExtendedRegister64, IR::Value(reg), value);
} else {
ASSERT_FALSE("Invalid reg.");
UNREACHABLE();
}
}
@@ -240,7 +236,7 @@ IR::UAny IREmitter::ReadMemory(size_t bitsize, const IR::U32& vaddr, IR::AccType
case 64:
return ReadMemory64(vaddr, acc_type);
}
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) {
@@ -298,7 +294,7 @@ void IREmitter::WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny
case 64:
return WriteMemory64(vaddr, value, acc_type);
}
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) {

View File

@@ -21,7 +21,7 @@
namespace Dynarmic::A32 {
bool CondCanContinue(const ConditionalState cond_state, const A32::IREmitter& ir) {
ASSERT_MSG(cond_state != ConditionalState::Break, "Should never happen.");
ASSERT(cond_state != ConditionalState::Break && "Should never happen.");
if (cond_state == ConditionalState::None)
return true;

View File

@@ -71,7 +71,7 @@ IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
case 64:
return ir.Imm64(value);
default:
ASSERT_FALSE("Imm - get: Invalid bitsize");
UNREACHABLE();
}
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2020 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -69,7 +72,7 @@ std::optional<std::tuple<size_t, size_t, size_t>> DecodeType(Imm<4> type, size_t
}
return std::tuple<size_t, size_t, size_t>{4, 1, 2};
}
ASSERT_FALSE("Decode error");
UNREACHABLE();
}
} // namespace

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -93,7 +96,7 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
return UnpredictableInstruction();
}
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if ((!P || W) && n == t) {
return UnpredictableInstruction();
}
@@ -124,7 +127,7 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
// LDR <Rt>, [<Rn>, #+/-<Rm>]{!}
// LDR <Rt>, [<Rn>], #+/-<Rm>
bool TranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (m == Reg::PC) {
return UnpredictableInstruction();
}
@@ -182,7 +185,7 @@ bool TranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
return UnpredictableInstruction();
}
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if ((!P || W) && n == t) {
return UnpredictableInstruction();
}
@@ -207,7 +210,7 @@ bool TranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
// LDRB <Rt>, [<Rn>, #+/-<Rm>]{!}
// LDRB <Rt>, [<Rn>], #+/-<Rm>
bool TranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
@@ -350,7 +353,7 @@ bool TranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R
// LDRH <Rt>, [PC, #-/+<imm>]
bool TranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (P == W) {
return UnpredictableInstruction();
}
@@ -380,7 +383,7 @@ bool TranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
return UnpredictableInstruction();
}
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if ((!P || W) && n == t) {
return UnpredictableInstruction();
}
@@ -405,7 +408,7 @@ bool TranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
// LDRH <Rt>, [<Rn>, #+/-<Rm>]{!}
// LDRH <Rt>, [<Rn>], #+/-<Rm>
bool TranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
@@ -454,7 +457,7 @@ bool TranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n,
return UnpredictableInstruction();
}
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if ((!P || W) && n == t) {
return UnpredictableInstruction();
}
@@ -479,7 +482,7 @@ bool TranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n,
// LDRSB <Rt>, [<Rn>, #+/-<Rm>]{!}
// LDRSB <Rt>, [<Rn>], #+/-<Rm>
bool TranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
@@ -527,7 +530,7 @@ bool TranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n,
return UnpredictableInstruction();
}
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if ((!P || W) && n == t) {
return UnpredictableInstruction();
}
@@ -552,7 +555,7 @@ bool TranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n,
// LDRSH <Rt>, [<Rn>, #+/-<Rm>]{!}
// LDRSH <Rt>, [<Rn>], #+/-<Rm>
bool TranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
ASSERT(!(!P && W) && "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -31,7 +34,7 @@ bool TranslatorVisitor::arm_MRS(Cond cond, Reg d) {
// MSR<c> <spec_reg>, #<const>
bool TranslatorVisitor::arm_MSR_imm(Cond cond, unsigned mask, int rotate, Imm<8> imm8) {
ASSERT_MSG(mask != 0, "Decode error");
ASSERT(mask != 0 && "Decode error");
if (!ArmConditionPassed(cond)) {
return true;

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -684,7 +687,7 @@ bool TranslatorVisitor::thumb16_NOP() {
// IT{<x>{<y>{<z>}}} <cond>
bool TranslatorVisitor::thumb16_IT(Imm<8> imm8) {
ASSERT_MSG((imm8.Bits<0, 3>() != 0b0000), "Decode Error");
ASSERT((imm8.Bits<0, 3>() != 0b0000) && "Decode Error");
if (imm8.Bits<4, 7>() == 0b1111 || (imm8.Bits<4, 7>() == 0b1110 && mcl::bit::count_ones(imm8.Bits<0, 3>()) != 1)) {
return UnpredictableInstruction();
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -20,7 +23,7 @@ bool TranslatorVisitor::thumb32_TST_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
}
bool TranslatorVisitor::thumb32_AND_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
@@ -66,7 +69,7 @@ bool TranslatorVisitor::thumb32_MOV_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im
}
bool TranslatorVisitor::thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(n != Reg::PC, "Decode error");
ASSERT(n != Reg::PC && "Decode error");
if (d == Reg::PC) {
return UnpredictableInstruction();
}
@@ -97,7 +100,7 @@ bool TranslatorVisitor::thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im
}
bool TranslatorVisitor::thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(n != Reg::PC, "Decode error");
ASSERT(n != Reg::PC && "Decode error");
if (d == Reg::PC) {
return UnpredictableInstruction();
}
@@ -125,7 +128,7 @@ bool TranslatorVisitor::thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
}
bool TranslatorVisitor::thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
@@ -153,7 +156,7 @@ bool TranslatorVisitor::thumb32_CMN_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
}
bool TranslatorVisitor::thumb32_ADD_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
@@ -211,7 +214,7 @@ bool TranslatorVisitor::thumb32_CMP_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
}
bool TranslatorVisitor::thumb32_SUB_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}

View File

@@ -17,7 +17,7 @@ namespace Dynarmic::A32 {
using SaturationFunction = IR::ResultAndOverflow<IR::U32> (IREmitter::*)(const IR::U32&, size_t);
static bool Saturation(TranslatorVisitor& v, bool sh, Reg n, Reg d, Imm<5> shift_amount, size_t saturate_to, SaturationFunction sat_fn) {
ASSERT_MSG(!(sh && shift_amount == 0), "Invalid decode");
ASSERT(!(sh && shift_amount == 0) && "Invalid decode");
if (d == Reg::PC || n == Reg::PC) {
return v.UnpredictableInstruction();

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -20,7 +23,7 @@ bool TranslatorVisitor::thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
}
bool TranslatorVisitor::thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
@@ -64,7 +67,7 @@ bool TranslatorVisitor::thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2,
}
bool TranslatorVisitor::thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(n != Reg::PC, "Decode error");
ASSERT(n != Reg::PC && "Decode error");
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
@@ -94,7 +97,7 @@ bool TranslatorVisitor::thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2,
}
bool TranslatorVisitor::thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(n != Reg::PC, "Decode error");
ASSERT(n != Reg::PC && "Decode error");
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
@@ -122,7 +125,7 @@ bool TranslatorVisitor::thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
}
bool TranslatorVisitor::thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
@@ -165,7 +168,7 @@ bool TranslatorVisitor::thumb32_CMN_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
}
bool TranslatorVisitor::thumb32_ADD_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
@@ -221,7 +224,7 @@ bool TranslatorVisitor::thumb32_CMP_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
}
bool TranslatorVisitor::thumb32_SUB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
ASSERT(!(d == Reg::PC && S) && "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -1301,11 +1304,11 @@ bool TranslatorVisitor::vfp_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo
// VSTM{mode}<c> <Rn>{!}, <list of double registers>
bool TranslatorVisitor::vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8) {
if (!p && !u && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p == u && w) {
@@ -1353,11 +1356,11 @@ bool TranslatorVisitor::vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, R
// VSTM{mode}<c> <Rn>{!}, <list of single registers>
bool TranslatorVisitor::vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8) {
if (!p && !u && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p == u && w) {
@@ -1396,11 +1399,11 @@ bool TranslatorVisitor::vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, R
// VLDM{mode}<c> <Rn>{!}, <list of double registers>
bool TranslatorVisitor::vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8) {
if (!p && !u && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p == u && w) {
@@ -1446,11 +1449,11 @@ bool TranslatorVisitor::vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, R
// VLDM{mode}<c> <Rn>{!}, <list of single registers>
bool TranslatorVisitor::vfp_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8) {
if (!p && !u && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p && !w) {
ASSERT_MSG(false, "Decode error");
ASSERT(false && "Decode error");
}
if (p == u && w) {

View File

@@ -77,7 +77,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
}
}
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
ASSERT(block.HasTerminal() && "Terminal has not been set");
block.SetEndLocation(visitor.ir.current_location);

View File

@@ -176,7 +176,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb,
}
}
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
ASSERT(block.HasTerminal() && "Terminal has not been set");
block.SetEndLocation(visitor.ir.current_location);

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -41,7 +44,7 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory
visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location});
}
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
ASSERT(block.HasTerminal() && "Terminal has not been set");
block.SetEndLocation(*visitor.ir.current_location);

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -75,9 +78,8 @@ IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
return ir.Imm32(static_cast<u32>(value));
case 64:
return ir.Imm64(value);
default:
ASSERT_FALSE("Imm - get: Invalid bitsize");
}
UNREACHABLE();
}
IR::UAny TranslatorVisitor::X(size_t bitsize, Reg reg) {
@@ -90,9 +92,8 @@ IR::UAny TranslatorVisitor::X(size_t bitsize, Reg reg) {
return ir.GetW(reg);
case 64:
return ir.GetX(reg);
default:
ASSERT_FALSE("X - get: Invalid bitsize");
}
UNREACHABLE();
}
void TranslatorVisitor::X(size_t bitsize, Reg reg, IR::U32U64 value) {
@@ -103,9 +104,8 @@ void TranslatorVisitor::X(size_t bitsize, Reg reg, IR::U32U64 value) {
case 64:
ir.SetX(reg, value);
return;
default:
ASSERT_FALSE("X - set: Invalid bitsize");
}
UNREACHABLE();
}
IR::U32U64 TranslatorVisitor::SP(size_t bitsize) {
@@ -114,9 +114,8 @@ IR::U32U64 TranslatorVisitor::SP(size_t bitsize) {
return ir.LeastSignificantWord(ir.GetSP());
case 64:
return ir.GetSP();
default:
ASSERT_FALSE("SP - get : Invalid bitsize");
}
UNREACHABLE();
}
void TranslatorVisitor::SP(size_t bitsize, IR::U32U64 value) {
@@ -128,7 +127,7 @@ void TranslatorVisitor::SP(size_t bitsize, IR::U32U64 value) {
ir.SetSP(value);
break;
default:
ASSERT_FALSE("SP - set : Invalid bitsize");
UNREACHABLE();
}
}
@@ -140,9 +139,8 @@ IR::U128 TranslatorVisitor::V(size_t bitsize, Vec vec) {
return ir.GetD(vec);
case 128:
return ir.GetQ(vec);
default:
ASSERT_FALSE("V - get : Invalid bitsize");
}
UNREACHABLE();
}
void TranslatorVisitor::V(size_t bitsize, Vec vec, IR::U128 value) {
@@ -157,9 +155,8 @@ void TranslatorVisitor::V(size_t bitsize, Vec vec, IR::U128 value) {
case 128:
ir.SetQ(vec, value);
return;
default:
ASSERT_FALSE("V - Set : Invalid bitsize");
}
UNREACHABLE();
}
IR::UAnyU128 TranslatorVisitor::V_scalar(size_t bitsize, Vec vec) {
@@ -232,9 +229,8 @@ IR::UAnyU128 TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccTyp
return ir.ReadMemory64(address, acc_type);
case 16:
return ir.ReadMemory128(address, acc_type);
default:
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
}
UNREACHABLE();
}
void TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccType acc_type, IR::UAnyU128 value) {
@@ -254,9 +250,8 @@ void TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccType acc_ty
case 16:
ir.WriteMemory128(address, value, acc_type);
return;
default:
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
}
UNREACHABLE();
}
IR::UAnyU128 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccType acc_type) {
@@ -271,9 +266,8 @@ IR::UAnyU128 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, I
return ir.ExclusiveReadMemory64(address, acc_type);
case 16:
return ir.ExclusiveReadMemory128(address, acc_type);
default:
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
}
UNREACHABLE();
}
IR::U32 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccType acc_type, IR::UAnyU128 value) {
@@ -288,9 +282,8 @@ IR::U32 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::Ac
return ir.ExclusiveWriteMemory64(address, value, acc_type);
case 16:
return ir.ExclusiveWriteMemory128(address, value, acc_type);
default:
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
}
UNREACHABLE();
}
IR::U32U64 TranslatorVisitor::SignExtend(IR::UAny value, size_t to_size) {
@@ -299,9 +292,8 @@ IR::U32U64 TranslatorVisitor::SignExtend(IR::UAny value, size_t to_size) {
return ir.SignExtendToWord(value);
case 64:
return ir.SignExtendToLong(value);
default:
ASSERT_FALSE("Invalid size parameter {}", to_size);
}
UNREACHABLE();
}
IR::U32U64 TranslatorVisitor::ZeroExtend(IR::UAny value, size_t to_size) {
@@ -310,9 +302,8 @@ IR::U32U64 TranslatorVisitor::ZeroExtend(IR::UAny value, size_t to_size) {
return ir.ZeroExtendToWord(value);
case 64:
return ir.ZeroExtendToLong(value);
default:
ASSERT_FALSE("Invalid size parameter {}", to_size);
}
UNREACHABLE();
}
IR::U32U64 TranslatorVisitor::ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount) {

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -70,15 +73,8 @@ bool MultiplyByElementHalfPrecision(TranslatorVisitor& v, Imm<1> L, Imm<1> M, Im
// TODO: Currently we don't implement half-precision paths
// for regular multiplication and extended multiplication.
if (extra_behavior == ExtraBehavior::None) {
ASSERT_FALSE("half-precision option unimplemented");
}
if (extra_behavior == ExtraBehavior::MultiplyExtended) {
ASSERT_FALSE("half-precision option unimplemented");
}
ASSERT(extra_behavior != ExtraBehavior::None
&& extra_behavior != ExtraBehavior::MultiplyExtended);
if (extra_behavior == ExtraBehavior::Subtract) {
operand1 = v.ir.FPNeg(operand1);
}

View File

@@ -30,7 +30,7 @@ public:
explicit Imm(u32 value)
: value(value) {
ASSERT_MSG((mcl::bit::get_bits<0, bit_size - 1>(value) == value), "More bits in value than expected");
ASSERT((mcl::bit::get_bits<0, bit_size - 1>(value) == value) && "More bits in value than expected");
}
template<typename T = u32>

View File

@@ -144,12 +144,12 @@ public:
}
/// Sets the terminal instruction for this basic block.
inline void SetTerminal(Terminal term) noexcept {
ASSERT_MSG(!HasTerminal(), "Terminal has already been set.");
ASSERT(!HasTerminal() && "Terminal has already been set.");
terminal = std::move(term);
}
/// Replaces the terminal instruction for this basic block.
inline void ReplaceTerminal(Terminal term) noexcept {
ASSERT_MSG(HasTerminal(), "Terminal has not been set.");
ASSERT(HasTerminal() && "Terminal has not been set.");
terminal = std::move(term);
}
/// Determines whether or not this basic block has a terminal instruction.

View File

@@ -124,7 +124,7 @@ public:
ASSERT(value.GetType() == Type::U64);
return value;
}
ASSERT_FALSE("Invalid bitsize");
UNREACHABLE();
}
U32 LeastSignificantWord(const U64& value) {
@@ -992,7 +992,7 @@ public:
}
UAny VectorGetElement(size_t esize, const U128& a, size_t index) {
ASSERT_MSG(esize * index < 128, "Invalid index");
ASSERT(esize * index < 128 && "Invalid index");
switch (esize) {
case 8:
return Inst<U8>(Opcode::VectorGetElement8, a, Imm8(static_cast<u8>(index)));
@@ -1008,7 +1008,7 @@ public:
}
U128 VectorSetElement(size_t esize, const U128& a, size_t index, const IR::UAny& elem) {
ASSERT_MSG(esize * index < 128, "Invalid index");
ASSERT(esize * index < 128 && "Invalid index");
switch (esize) {
case 8:
return Inst<U128>(Opcode::VectorSetElement8, a, Imm8(static_cast<u8>(index)), elem);
@@ -1114,7 +1114,7 @@ public:
}
U128 VectorBroadcastElementLower(size_t esize, const U128& a, size_t index) {
ASSERT_MSG(esize * index < 128, "Invalid index");
ASSERT(esize * index < 128 && "Invalid index");
switch (esize) {
case 8:
return Inst<U128>(Opcode::VectorBroadcastElementLower8, a, u8(index));
@@ -1127,7 +1127,7 @@ public:
}
U128 VectorBroadcastElement(size_t esize, const U128& a, size_t index) {
ASSERT_MSG(esize * index < 128, "Invalid index");
ASSERT(esize * index < 128 && "Invalid index");
switch (esize) {
case 8:
return Inst<U128>(Opcode::VectorBroadcastElement8, a, u8(index));

View File

@@ -42,8 +42,10 @@ Type Inst::GetType() const {
}
void Inst::SetArg(size_t index, Value value) noexcept {
DEBUG_ASSERT_MSG(index < GetNumArgsOf(op), "Inst::SetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
DEBUG_ASSERT_MSG(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)), "Inst::SetArg: type {} of argument {} not compatible with operation {} ({})", value.GetType(), index, op, GetArgTypeOf(op, index));
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)));
//DEBUG_ASSERT(index < GetNumArgsOf(op) && "Inst::SetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
//DEBUG_ASSERT(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)) && "Inst::SetArg: type {} of argument {} not compatible with operation {} ({})", value.GetType(), index, op, GetArgTypeOf(op, index));
if (!args[index].IsImmediate()) {
UndoUse(args[index]);
}
@@ -79,7 +81,7 @@ void Inst::Use(const Value& value) {
if (IsAPseudoOperation(op)) {
if (op == Opcode::GetNZCVFromOp) {
ASSERT_MSG(MayGetNZCVFromOp(value.GetInst()->GetOpcode()), "This value doesn't support the GetNZCVFromOp pseduo-op");
ASSERT(MayGetNZCVFromOp(value.GetInst()->GetOpcode()) && "This value doesn't support the GetNZCVFromOp pseduo-op");
}
Inst* insert_point = value.GetInst();

View File

@@ -53,8 +53,10 @@ public:
}
inline Value GetArg(size_t index) const noexcept {
DEBUG_ASSERT_MSG(index < GetNumArgsOf(op), "Inst::GetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
DEBUG_ASSERT_MSG(!args[index].IsEmpty() || GetArgTypeOf(op, index) == IR::Type::Opaque, "Inst::GetArg: index {} is empty", index, args[index].GetType());
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(!args[index].IsEmpty() || GetArgTypeOf(op, index) == IR::Type::Opaque);
//DEBUG_ASSERT(index < GetNumArgsOf(op) && "Inst::GetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
//DEBUG_ASSERT(!args[index].IsEmpty() || GetArgTypeOf(op, index) == IR::Type::Opaque && "Inst::GetArg: index {} is empty", index, args[index].GetType());
return args[index];
}
void SetArg(size_t index, Value value) noexcept;

View File

@@ -1466,7 +1466,7 @@ static void VerificationPass(const IR::Block& block) {
for (size_t i = 0; i < inst.NumArgs(); i++) {
const IR::Type t1 = inst.GetArg(i).GetType();
const IR::Type t2 = IR::GetArgTypeOf(inst.GetOpcode(), i);
ASSERT_MSG(IR::AreTypesCompatible(t1, t2), "Block failed:\n{}", IR::DumpBlock(block));
ASSERT(IR::AreTypesCompatible(t1, t2));
}
}
ankerl::unordered_dense::map<IR::Inst*, size_t> actual_uses;

View File

@@ -70,7 +70,7 @@ bool AnyLocationDescriptorForTerminalHas(IR::Terminal terminal, Fn fn) {
} else if constexpr (std::is_same_v<T, IR::Term::CheckHalt>) {
return AnyLocationDescriptorForTerminalHas(t.else_, fn);
} else {
ASSERT_MSG(false, "Invalid terminal type");
ASSERT(false && "Invalid terminal type");
return false;
}
}, terminal);
@@ -282,7 +282,7 @@ std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s
} else if (bitstring.substr(0, 8) == "11110100") {
bitstring.replace(0, 8, "11111001");
} else {
ASSERT_FALSE("Unhandled ASIMD instruction: {} {}", fn, bs);
UNREACHABLE(); // "Unhandled ASIMD instruction: {} {}", fn, bs);
}
if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
invalid.emplace_back(InstructionGenerator{bitstring.c_str()});

View File

@@ -97,11 +97,17 @@ public:
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
}
void InterpreterFallback(u32 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:08x}, {}) code = {:08x}", pc, num_instructions, *MemoryReadCode(pc)); }
void InterpreterFallback(u32 pc, size_t num_instructions) override {
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:08x} && {}) code = {:08x}", pc, num_instructions, *MemoryReadCode(pc));
}
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception /*exception*/) override { ASSERT_MSG(false, "ExceptionRaised({:08x}) code = {:08x}", pc, *MemoryReadCode(pc)); }
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception /*exception*/) override {
UNREACHABLE(); //ASSERT(false && "ExceptionRaised({:08x}) code = {:08x}", pc, *MemoryReadCode(pc));
}
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {
@@ -184,11 +190,17 @@ public:
return true;
}
void InterpreterFallback(std::uint32_t pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void InterpreterFallback(std::uint32_t pc, size_t num_instructions) override {
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:016x} && {})", pc, num_instructions);
}
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
}
void ExceptionRaised(std::uint32_t pc, Dynarmic::A32::Exception) override { ASSERT_MSG(false, "ExceptionRaised({:016x})", pc); }
void ExceptionRaised(std::uint32_t pc, Dynarmic::A32::Exception) override {
UNREACHABLE(); //ASSERT(false && "ExceptionRaised({:016x})", pc);
}
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {

View File

@@ -105,11 +105,17 @@ public:
return true;
}
void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void InterpreterFallback(u64 pc, size_t num_instructions) override {
UNREACHABLE(); // ASSERT(false&& "InterpreterFallback({:016x} && {})", pc, num_instructions);
}
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception /*exception*/) override { ASSERT_MSG(false, "ExceptionRaised({:016x})", pc); }
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception /*exception*/) override {
UNREACHABLE(); //ASSERT(false && "ExceptionRaised({:016x})", pc);
}
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {
@@ -202,11 +208,17 @@ public:
return true;
}
void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(ignore_invalid_insn, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void InterpreterFallback(u64 pc, size_t num_instructions) override {
ASSERT(ignore_invalid_insn && "InterpreterFallback");
}
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception) override { ASSERT_MSG(false, "ExceptionRaised({:016x})", pc); }
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception) override {
UNREACHABLE(); //ASSERT(false && "ExceptionRaised({:016x})", pc);
}
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {

View File

@@ -306,7 +306,7 @@ std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s
} else if (bitstring.substr(0, 8) == "11110100") {
bitstring.replace(0, 8, "11111001");
} else {
ASSERT_FALSE("Unhandled ASIMD instruction: {} {}", fn, bs);
UNREACHABLE(); // "Unhandled ASIMD instruction: {} {}", fn, bs);
}
if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
invalid.emplace_back(InstructionGenerator{bitstring.c_str()});

View File

@@ -18,7 +18,7 @@
#define CHECKED(expr) \
do { \
if (auto cerr_ = (expr)) { \
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", static_cast<size_t>(cerr_), \
ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast<size_t>(cerr_), \
uc_strerror(cerr_)); \
} \
} while (0)

View File

@@ -13,7 +13,7 @@
#define CHECKED(expr) \
do { \
if (auto cerr_ = (expr)) { \
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", static_cast<size_t>(cerr_), \
ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast<size_t>(cerr_), \
uc_strerror(cerr_)); \
} \
} while (0)

View File

@@ -810,15 +810,16 @@ void Room::RoomImpl::BroadcastRoomInformation() {
}
IPv4Address Room::RoomImpl::GenerateFakeIPAddress() {
IPv4Address result_ip{192, 168, 0, 0};
std::uniform_int_distribution<> dis(0x01, 0xFE); // Random byte between 1 and 0xFE
do {
for (std::size_t i = 2; i < result_ip.size(); ++i) {
result_ip[i] = static_cast<u8>(dis(random_gen));
// An IP address is valid if it is not already taken by anybody else in the room.
std::lock_guard lock(member_mutex);
for (u8 i = 0x01; i < 0xFF; ++i)
for (u8 j = 0x01; j < 0xFF; ++j) {
IPv4Address addr{192, 168, i, j};
if (std::all_of(members.begin(), members.end(), [&addr](auto const& member) { return member.fake_ip != addr; }))
return addr;
}
} while (!IsValidFakeIPAddress(result_ip));
return result_ip;
LOG_ERROR(Network, "All addresses are taken");
return IPv4Address{192, 168, 0, 0};
}
void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) {

View File

@@ -647,6 +647,8 @@ LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
return {};
}
ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS));
if (info.resources.levels > static_cast<s32>(MAX_MIP_LEVELS))
return {};
const LevelInfo level_info = MakeLevelInfo(info);
LevelArray offsets{};
u32 offset = 0;