Compare commits
11 Commits
discfix
...
v0.0.4-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa93e0cbb1 | ||
|
|
ead5978b34 | ||
|
|
bfb112dad1 | ||
|
|
2d3ba3e5dd | ||
|
|
36b736482a | ||
|
|
dbc98f758e | ||
|
|
84db3351ab | ||
|
|
3a54d322ab | ||
|
|
f9773fa908 | ||
|
|
2dc6d773ee | ||
|
|
402d8e833d |
10
.github/ISSUE_TEMPLATE/config.yml
vendored
10
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -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.
|
||||
|
||||
@@ -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).**
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = {}) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -128,7 +128,7 @@ void A32AddressSpace::Link(EmittedBlockInfo& block_info) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_FALSE("Invalid relocation target");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ struct Jit::Impl final {
|
||||
|
||||
private:
|
||||
void RequestCacheInvalidation() {
|
||||
// ASSERT_FALSE("Unimplemented");
|
||||
// UNREACHABLE();
|
||||
|
||||
invalidate_entire_cache = false;
|
||||
invalid_cache_ranges.clear();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -323,4 +323,8 @@ void Jit::ClearExclusiveState() {
|
||||
impl->ClearExclusiveState();
|
||||
}
|
||||
|
||||
std::string Jit::Disassemble() const {
|
||||
return impl->Disassemble();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -55,9 +55,6 @@ struct OpArg {
|
||||
case 64:
|
||||
inner_reg = inner_reg.cvt64();
|
||||
return;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid bits");
|
||||
return;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()});
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user