Compare commits

..

14 Commits

Author SHA1 Message Date
lizzie aa6178c0c9 [scarletnx] Add CPU backend
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Assisted-by: Claude Opus 5.5 <claude@anthropic.com>
2026-10-25 17:53:53 +00:00
PavelBARABANOV eb88a40a8e [qt] fix graphics API toggle getting stuck on OpenGL_GLSL (#4577)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4577
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-25 16:06:46 +01:00
PavelBARABANOV 305f40100d Fix aarch and android builds (#4576)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
credit: John and Crueter

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4576
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-25 10:03:16 +01:00
John 989768aa46 Fix [core, gpu, threads] Multithreading refactor (#4254) (#4548)
Performance loss regression fixed in Link's Awakening, Castlevania, Super Mario RPG, etc

Tested by Mr. Knobs on Android and myself on Linux

Multicore ON may be fixed for some users using Intel CPUs.
Games include: FF Tactics, Shredder's Revenge, Unity Engine Games.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4548
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-19 15:58:04 +02:00
John de7e6e01d4 Revert [input_common/joycon] Enumerate SDL devices iff SDL signals change (#4486) (#4545)
Due to causing the platform windows to crash when a controller is activated.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Co-authored-by: Your Name <John@John.localdomain>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4545
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-10-18 00:17:28 +02:00
crueter e0d47f2790 [cmake] fix macOS compilation by forcing lz4 to be static (#4540)
Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4540
2026-10-16 21:41:11 +02:00
PavelBARABANOV d8c6c59b67 Fix Check Strings after 4523 (#4534)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4534
2026-10-16 01:17:53 +02:00
xbzk aaa0bcb9bf [patcher, ro, settings] runtime tls patch (#4492) optimization and nuke toggle (#4502) (#4523)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
This is a follow up for the biomutant fix. By the time i knew it was shallow, coz i was running patchtext routine even for svc and modules, causing a routine which were needed to run 14 times to run 4000+ instead.
Since some perf loss was reported in 30 sep nightly, and it caused ac3r to not boot, we had added a temp toggle, which is now being removed as optimizations + fix are in.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4523
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-15 12:13:17 +02:00
PavelBARABANOV e255c20db4 Revert "[hle] constexpr handler dispatch maps, introduce version gating (#4480)" (#4532)
This reverts commit 218c6705d9.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4532
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-10-15 08:45:15 +02:00
lizzie 14da4482a4 [input_common/joycon] Enumerate SDL devices iff SDL signals change (#4486)
As per SDL documentation this is the "desired" loop.

> Enumerating the HID devices is an expensive operation, so you can call this to see if there have been any system device changes since the last call to this function. A change in the counter returned doesn't necessarily mean that anything has changed, but you can call SDL_hid_enumerate() to get an updated device list.

https://wiki.libsdl.org/SDL3/SDL_hid_device_change_count

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

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4486
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-14 21:24:58 +02:00
lizzie fb51a12534 [input/sdl] nuke SDL_Vibration thread (#4299)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

isn't it net faster to just...send things, serially?
especially since vibration occurs so non-often...
i dont think it would cause any issues

TEST: if this causes ANY sort of perf regression on games
when the thing vibrates WITH AN SDL CONFIGURED GAMEPAD OR WHATEVER

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4299
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-14 21:24:35 +02:00
CamilleLaVey a594c8d60e [shader_recompiler, vulkan, qcom, tu] Provide handling to missing shader subgroups on QCOM (#4508)
This works provides better emulation on certain GS missing for shader invocation data + geometry pass fallback in qcom/turnip drivers, some of those were provided as community patch by @a.kamaltdinov; which was refined to address the requirements on forced gpu reads; which used to kill some performance on low end devices; now, the stability with some of the graphical problems have been addressed and balanced. Shuffle shaders (SHFFL) are not actually provided on QCOM and turnip drivers, so any game that previously required this stage draw, will now avoid being ignored and tax some performance based on the complexity of the stage draw from now on. This will also address partially some tessellation problems as well.

_Special Thanks:_

1.- @a.kamaltdinov (for the initial patch "early fix for nier" provided for #4325)
2.- @PavelBARABANOV (because the making the cherry-pick easier for a new PR)

Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4508
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-14 00:04:16 +02:00
crueter 6b3cb5772b [docs] revise AI policy (#4522)
spent 2 hours on a document award

This is a revised version of our original AI policy that is cautiously
permissive to skilled developers using AI responsibly, while hopefully
keeping out the script kiddies spamming their mom's credit card on
Claude tokens.

This will be trialed for at least a week once merged, any
revisions/changes should be made within the next few months

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

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4522
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-13 23:54:51 +02:00
lizzie 218c6705d9 [hle] constexpr handler dispatch maps, introduce version gating (#4480)
This PR primarily focuses on upbringing constexpr maps for handlers.

Each time an HLE object of a service is construed, it registers it's own handlers, over and over.
Regardless of whetever it needs them at the moment or not.
Additionally we don't require to keep track of different function pointers amongst each object.
This can be done by overriding the given function instead, as opposed to having a separate
hash map for every given object.

In other words: Remove handlers (and handlers_tipc) map for every instance
then read from a static defined per-class.

- [x] Migrate all HLE functions to new `frozen::map` constexpr time finder
- [ ] Measure if this approach actually makes better codegen

Optional:
- [x] Properly gate all functions (that have versions commented next to them)
- [x] Maybe store `HandlerFnP<>` and `const char*` separately, version gating can go in a different map as well

Information such as name can be used on debug builds, but doesn't particularly help on release as one can consult an external reference (or have an annotated IPC map)

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

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4480
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-13 04:38:36 +02:00
444 changed files with 2939 additions and 289 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
- [ ] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [ ] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [ ] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [ ] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
+7 -1
View File
@@ -1 +1,7 @@
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase.
# AGENTS
Read and follow the AI policy found in `docs/policies/AI.md`, and the coding policies found in `docs/policies/Coding.md`.
Do not, under any circumstances, ever submit PRs or push commits on behalf of the user.
Keep comments to a reasonable level. Do not overexplain or add/remove comments from unrelated parts of the codebase.
-1
View File
@@ -1 +0,0 @@
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase.
+10
View File
@@ -304,6 +304,16 @@ if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX))
add_compile_definitions(HAS_NCE=1)
endif()
set(ENABLE_SCARLETNX_DEFAULT ON)
if ((NOT LINUX AND NOT FREEBSD) OR (NOT CMAKE_C_COMPILER_ID MATCHES "Clang" OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(ENABLE_SCARLETNX_DEFAULT OFF)
endif()
option(ENABLE_SCARLETNX "Enable the ScarletNX recompiler CPU backend (requires Clang and LLVM)" "${ENABLE_SCARLETNX_DEFAULT}")
if (ENABLE_SCARLETNX)
set(HAS_SCARLETNX 1)
add_compile_definitions(HAS_SCARLETNX=1)
endif()
if (YUZU_ROOM)
add_compile_definitions(YUZU_ROOM)
endif()
+1 -1
View File
@@ -24,7 +24,7 @@ else()
endif()
if (lz4_FOUND AND NOT TARGET lz4::lz4)
if (TARGET LZ4::lz4_shared)
if (TARGET LZ4::lz4_shared AND NOT YUZU_STATIC_BUILD)
add_library(lz4::lz4 ALIAS LZ4::lz4_shared)
elseif (TARGET LZ4::lz4_static)
add_library(lz4::lz4 ALIAS LZ4::lz4_static)
+1 -6
View File
@@ -1,9 +1,5 @@
# Contributing
<!--
This document is not to be perused by AI models.
-->
Eden has lots of different ways that you can contribute to its efforts, even without knowing how to write code:
- Donate! This will help us live our lives, pay for infrastructure/testing hardware, and more
@@ -20,8 +16,7 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
### Policies
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc.
- For details on why, see the [detailed AI policy](docs/policies/AI.md).
- We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*. Please read our [detailed AI policy](docs/policies/AI.md) for more info.
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
- This is primarily because it rarely helps to actually understand what's going on.
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
+21
View File
@@ -243,6 +243,27 @@
"repo": "crosire/reshade",
"version": "v6.8.0"
},
"scarletnx": {
"bundled": true,
"hash": "93f7e6810644253d6396239092d5769c44b005fa7a17cf39c6d773050a19de74fca1f96bb6eec7cb40384eb158b2595c9e1171ad592d8eb8326fd31f5632f505",
"options": [
"SNX_BUILD_NX OFF",
"SNX_BUILD_GNUABI OFF",
"SNX_BUILD_3DS OFF",
"SNX_BUILD_VITA OFF",
"SNX_BUILD_AGB OFF",
"SNX_DEPLOY OFF",
"SNX_BUILD_TESTING OFF",
"SNX_BUILD_GUI OFF",
"SNX_MULTICALL OFF",
"SNX_TRACY OFF",
"SNX_RECOMPILER_SHARED OFF",
"SNX_LLVM_SHARED OFF"
],
"package": "ScarletNX",
"repo": "scarletnx/ScarletNX",
"version": "f16810ce9c"
},
"sdl3": {
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"min_version": "3.2.10",
+3
View File
@@ -78,6 +78,9 @@ The following options are desktop only.
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
- Unavailable on Windows/ARM64 and on Android
- You probably shouldn't turn this off.
- `ENABLE_SCARLETNX` (OFF) Enable the ScarletNX recompiler
- Requires Clang and LLVM's development files
- Needs multicore and fastmem
### Qt
+143 -56
View File
@@ -1,65 +1,159 @@
# AI Policy
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase.
> [!WARNING]
> We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*.
> This policy is subject to change at any point in time, so check back frequently.
>
> This banner will be removed once we have finalized our revised policy.
- [AI Policy](#ai-policy)
- [Low-quality code](#low-quality-code)
- [Licensing concerns](#licensing-concerns)
- [Vibe-coding](#vibe-coding)
- [Commit messages](#commit-messages)
- [Miscellaneous concerns](#miscellaneous-concerns)
- [Unacceptable Use Examples](#unacceptable-use-examples)
- [Addendum: Commit Messages](#addendum-commit-messages)
- [TL;DR](#tldr)
- [Definitions](#definitions)
- [Scope](#scope)
- [Introduction](#introduction)
- [Requirements](#requirements)
- [Sign-off, Authorship, and Copyright](#sign-off-authorship-and-copyright)
- [Permitted Usage](#permitted-usage)
- [Recommended Prior Discussion](#recommended-prior-discussion)
- [Forbidden Usage](#forbidden-usage)
- [Human Effort Denial of Service](#human-effort-denial-of-service)
- [Disclosure](#disclosure)
- [Codebase Ingestion](#codebase-ingestion)
- [Enforcement](#enforcement)
- [Addendum: AI Commit Messages](#addendum-ai-commit-messages)
- [References](#references)
## Low-quality code
## TL;DR
AI is notorious for producing low-quality code; be it:
AI-assisted contributions are welcome, provided you take responsibility for them.
- nonfunctional,
- verbose/inefficient,
- breaking other parts of the codebase,
- or writing/architecting in a completely different style
- You **must** disclose any AI or LLM usage in your pull request description *and* commit message.
- You **must** be able to explain, defend, and revise every line of code you submit.
- Commit messages, PR descriptions, issues, and comments **must** be written by you. Verbatim AI output is not acceptable.
- Undisclosed AI usage will result in your contribution being rejected.
- Low-quality contributions, disclosed or not, will be reworked or rejected.
- Spamming automated PRs, comments, or issues is treated as a Denial of Service (DoS) attack on our reviewers; see [Human Effort Denial of Service](#human-effort-denial-of-service).
All code, AI or not, is held under a **strict standard of excellence**. AI/LLM-generated code will fail this test 10 times out of 10.
## Definitions
## Licensing concerns
An *AI or LLM-based tool* is any piece of software that generates code, text, or other content through machine learning models. This includes, but is not limited to: chat assistants, agentic coding tools/harnesses, inline code completion suggestions you have accepted into the code, and AI-driven explanation/refactoring features.
This is an area of ongoing litigation, and as such, is still very iffy. For the time being, know that allowing AI to ingest the codebase may end up with its copyleft code regurgitated into incompatibly-licensed proprietary or permissive software. For you, this means to **not** feed code into LLMs.
For the purposes of this policy, basic deterministic/static development tools (such as clang-tidy, git, compilers, etc.) are not considered AI tools.
AI models may have also ingested AGPLv3 code, which is license-incompatible with our codebase.
Terms such as "substantially", "large-scale", "majority", and "low-quality" are intentionally left vague, and will be interpreted at the maintainers' discretion. When in doubt, ask first.
## Vibe-coding
## Scope
Just don't. If you're not going to put the effort in to understand every line of code you wrote, neither will we, and your patch or pull request will be ignored.
This policy applies to all code contributions, alongside issues and pull requests surrounding this codebase. This includes:
## Commit messages
- Commit messages
- PR descriptions
- Code review comments
- Issue/PR comments
- Patches submitted via e-mail
AI-generated commit messages are absolutely terrible, and your pull request or patch will immediately be rejected if you choose to do this. They are, quite simply, actively detrimental to our understanding of your changes, and if you're not willing to summarize the intent behind your changes, then we're not going to bother reading the code you wrote.
Areas that are not directly related to code--such as our surrounding communities--are not covered by the terms of this policy. Additionally, spelling/grammar checking via AI or LLM-based tools is not covered under this document.
Write concise, simple, and descriptive commit messages that actually convey the proper intent behind what your change is trying to do.
## Introduction
See the [Addendum](#addendum-commit-messages) for an instance of how bad AI models are at commit messages.
In the right hands, AI and LLM-based tools are incredibly useful for getting features and bugfixes out the door as fast as possible. At the same time, reviewer bandwidth is a scarce resource. We are therefore open to AI-assisted contributions, provided they are produced and disclosed properly.
## Miscellaneous concerns
The goal of this document is *not* to set arbitrary restrictions, but rather to keep our development healthy and stable, while still allowing contributors to use the tools they find helpful. A contribution must be worth more to the project than the time it takes to review it.
- While many environmental concerns about AI are typically blown out of proportion, it *is* a legitimate issue, and should be taken into account.
- Many people have significant concerns over the ethics of AI usage due to inhumane and predatory behavior by large AI companies, particularly Anthropic and OpenAI. This can technically be avoided through the usage of local LLMs.
- LLMs have a tendency to add unicode characters (such as the arrow → and the em-dash — symbols) to their output, which can make viewing code or documents harder on command-line editors and viewers.
- Dedicated coding models--namely Claude--also like to add a lot of comments to overexplain every individual line of code it produces. This actually makes it *harder* to understand the code!
Throughout this document, **must** and **must not** are inflexible, binding requirements. Refusal to follow these is treated as a violation of the terms outlined in this document.
## Unacceptable Use Examples
## Requirements
Here are a few examples of unacceptable use:
These apply to all contributions, whether AI-assisted or not. AI-assisted contributions also carry additional disclosure requirements as outlined in [Disclosure](#disclosure).
- Solving problems
- Slapping a few files and a "please fix bug XYZ" into an LLM is a recipe for disaster that will pretty much never work.
- Fully AI-generated code, aka "vibecoding"
- Writing code based on pseudo-instructions
- If you don't know how to write code, don't. If you've figured out the root cause (preferably without feeding random files into an LLM) and actively know what's going on, provide information to other developers or friends of yours who have knowledge of the language and/or the codebase.
1. *Disclosure*. Any and all usage of AI or LLM-based tools within any contribution **must** be explicitly marked and disclosed as appropriate.
2. *Responsibility*. The human submitter of any contribution is held wholly responsible for the accuracy, completeness, and intent of what is submitted. You **must** be able to explain, defend, and revise your code during review.
3. *Review*. All code **must** be thoroughly reviewed by the author before opening a PR or marking it ready for review.
4. *Testing*. All code changes **must** be tested directly by the human author.
5. *Quality*. All submitted code is held to a strict standard of excellence. Low-quality AI-generated content does not uphold this standard.
6. *Licensing*. All code **must** be compatible with the GPLv3 or later. You **must** warrant that you have the right to submit it under those terms, and that it was not copied from work published under an incompatible license.
## Addendum: Commit Messages
## Sign-off, Authorship, and Copyright
The patchset for pull request [#3422](https://git.eden-emu.dev/eden-emu/eden/pulls/3422) was fed into several LLMs to generate a commit message. One LLM produced the following:
AI agents **must not** add `Signed-off-by:` tags. The human submitter **must** sign off on all changes.
Similarly, AI agents cannot hold authorship or copyright over code, and **must not** add `Co-authored-by:` or `Co-developed-by:` tags. The human submitter **must** author all changes.
## Permitted Usage
This is a non-exhaustive list of permitted uses of AI and LLM-based tools, provided they are disclosed properly.
- Drafting issues and pull requests, provided the final text and submitted code are substantially your own.
- Debugging issues, bugs, glitches, and crashes, whether pre-existing or introduced by your own changes.
- Reviewing your own changes before submitting a PR.
- Research, brainstorming, and codebase searching/understanding.
- Applying tedious but not particularly large changes, such as mass-migrating specific classes to polyfills or abstractions.
## Recommended Prior Discussion
Some usage cases are not necessarily forbidden nor permitted. These should be discussed with maintainers in an issue or e-mail *before* submission. Maintainers and reviewers may also comment on this during the review/submission phase.
- Generating boilerplate/scaffolding for new code.
- Writing unit tests.
- Large-scale refactors primarily driven by an AI agent.
- Any contribution where an AI agent or model was responsible for the majority of the implementation.
## Forbidden Usage
This is a non-exhaustive list of strictly forbidden uses of AI and LLM-based tools.
- Vibecoding, or changes entirely authored by AI agents without human intervention or understanding.
- If you don't choose to put in the necessary effort to understand every line of code you submitted, neither will we.
- Fully AI-generated commit messages, PR descriptions, issues, or comments. See [Addendum: AI Commit Messages](#addendum-ai-commit-messages).
- Submission of AI-assisted work that is not disclosed per the [Disclosure](#disclosure) requirements.
- Low-quality submissions that fail to satisfy our standard of code excellence.
- Submitting secrets, credentials, private user data, or unpublished security reports to third-party AI services.
- This includes console keys, encryption material, and private vulnerability disclosures.
- Verbatim AI code reviews (e.g. Codex/Copilot reviews).
## Human Effort Denial of Service
Using automated tools and AI to submit PRs, issues, and comments that we have to carefully review and handle is considered a [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) on our human effort.
It takes very little effort on your side (an LLM prompt) to generate a large amount of effort on ours (careful and thorough code review). Please respect our time and don't do that.
## Disclosure
How you disclose AI usage is up to you. However, it **must** be explicit, easy to identify, and placed both within the commit message *and* the surrounding PR description. For patches submitted by e-mail, the cover letter counts as the PR description. We recommend an `Assisted-by:` footer:
```txt
Assisted-by: <model> (<what it was used for>)
```
For instance:
```txt
Assisted-by: Claude Opus 5.5 (initial draft and code review)
```
Contributions without a commit message (e.g. issues/comments) should instead use a plain sentence in the text body such as `I used <model> to help with <X>`. PRs and commit messages may opt to use this format as well.
Multi-commit series/squashes **must** maintain the trailer. Maintainers will handle this for merges to master, but you are responsible for ensuring the disclosure survives into the final commit/PR body of squashes within your branches.
Regardless, what matters is that reviewers can tell *at a glance* where and how AI was involved in your contribution.
## Codebase Ingestion
Ingestion of this codebase by LLMs for any purpose--such as training or prompt context--is permitted *for now*. This may change at any point as litigation and court rulings around AI and code copyright proceed.
AI models may have ingested AGPLv3 or otherwise copyleft-incompatible code and may regurgitate it. You remain responsible for ensuring that all code you submit is compatible with the GPLv3 or later.
## Enforcement
- If we suspect undisclosed AI usage in a contribution, we will ask for disclosure.
- Refusal to provide disclosure will result in rejection of the contribution, and your PR or issue will be closed. Maintainers may choose to rework it themselves if the change is worth having.
- Accounts that spam us with repeated automated PRs or comments will be blocked or permanently suspended from our Git instance.
- Maintainers reserve the right to close your issues and pull requests if you don't follow the guidelines and procedures outlined in this document, and refuse or fail to make changes as necessary to comply.
- Repeated failures to comply may result in loss of contribution privileges.
## Addendum: AI Commit Messages
The patchset for pull request [#3422](https://git.eden-emu.dev/eden-emu/eden/pulls/3422) was fed into a dedicated code AI model, and it produced the following:
```txt
profile_manager: Refactor user deletion to use index instead of UUID
@@ -89,28 +183,21 @@ These changes eliminate redundant code, reduce the risk of UUID → index mismat
Fixes: potential inconsistency when user order changes between UI and backend
```
This is:
This:
- Needlessly verbose (nobody cares about most of these details)
- Is needlessly verbose (nobody cares about most of these details)
- Doesn't address the actual purpose of the PR (fixing a double-deletion bug in the profile manager)
- Has unicode arrows (this is bad for command-line editors)
- Uses corporate and word-salad language
- Uses corporate and word-salad language that pads out the message to make it look like a lot changed
Another (code-oriented) LLM output the following:
A good commit message should be concise, descriptive, and convey the *intent* behind the change, such as the bug being fixed or the feature being added. It should *not* be a detailed changelog of every individual byte that's changed.
```txt
profile(manager/ui): switch to index-based deletion and unify removal logic
## References
- Make ConfigureProfileManagerDeleteDialog emit a deleteUser(int) signal instead of taking a callback. Store the target index in the dialog (m_index) and emit it on acceptance.
- Change ConfigureProfileManager to pass an index to SetInfo and to accept an index in DeleteUser. Wire the dialog signal to the new DeleteUser slot.
- Update headers: add the signal and m_index, add TODO to move dialog to a .ui file, and update slot/signature declarations.
- Add ProfileManager::RemoveProfileAtIndex(std::size_t) and refactor RemoveUser(UUID) to call RemoveProfileAtIndex to avoid duplicated removal logic. Ensure the removal path marks saves as needed and writes the user save file.
- Ensure the profile list updates immediately after deletes by calling profile_manager.ResetUserSaveFile() when populating the user list (qlaunch fix).
- Misc: update SPDX copyright year and fix build breakages caused by the API changes.
This policy document has been adapted from the AI policies of numerous other free and open-source projects, whether restrictive or permissive.
This consolidates profile removal behavior, fixes potential race conditions in the profile dialog, and removes duplicated removal code.
```
This has all of the same problems as the other one. Needlessly verbose, doesn't address *what* it actually fixes ("consolidates profile removal behavior"... okay, why? What does it fix?), etc. It even has the bonus of totally hallucinating the addition of a method!
On a more "philosophical" note, LLMs tend to be geared towards *corporate language*, as that's what they're trained on. This is why AI-generated commit messages feel like "word salad", and typically pad out the commit message to make it *look* like a lot of things were changed (trust me, it's like that in the corporate world). They typically also drift towards unneeded buzzwords and useless implementation details.
- [Gitea](https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#ai-contribution-policy)
- The [Linux kernel](https://kernel.org/doc/html/next/process/coding-assistants.html)
- [Gentoo Linux](https://wiki.gentoo.org/wiki/Project:Council/AI_policy)
- [cURL](https://curl.se/dev/contribute.html#on-ai-use-in-curl)
- [FastAPI](https://tiangolo.com/open-source/contributing/#automated-code-and-ai)
+8
View File
@@ -249,6 +249,14 @@ if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2)
endif()
# ScarletNX
if (ENABLE_SCARLETNX)
AddJsonPackage(scarletnx)
if (TARGET scarletnx-recompiler)
set_target_properties(scarletnx-recompiler PROPERTIES SYSTEM ON)
endif()
endif()
# getopt
if (MSVC)
add_subdirectory(getopt)
+1 -1
View File
@@ -259,7 +259,7 @@ android {
externalNativeBuild {
cmake {
version = "3.31.6"
version = "3.31.5"
path = file("${edenDir}/CMakeLists.txt")
}
}
@@ -17,7 +17,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
NCE_RUNTIME_NRO_PATCH("nce_runtime_nro_patch"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"),
@@ -95,7 +94,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
ENABLE_QUICK_SETTINGS("enable_quick_settings");
// external fun isFrameSkippingEnabled(): Boolean
//external fun isFrameSkippingEnabled(): Boolean
external fun isFrameInterpolationEnabled(): Boolean
override fun getBoolean(needsGlobal: Boolean): Boolean =
@@ -866,13 +866,6 @@ abstract class SettingsItem(
descriptionId = R.string.nce_invalidation_gpu_readback_description
)
)
put(
SwitchSetting(
BooleanSetting.NCE_RUNTIME_NRO_PATCH,
titleId = R.string.nce_runtime_nro_patch,
descriptionId = R.string.nce_runtime_nro_patch_description
)
)
put(
SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -555,7 +555,6 @@ class SettingsFragmentPresenter(
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
add(BooleanSetting.NCE_RUNTIME_NRO_PATCH.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
@@ -589,8 +589,6 @@
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
<string name="nce_invalidation_gpu_readback">إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية NCE</string>
<string name="nce_invalidation_gpu_readback_description">إصلاح مؤقت. يعالج مشكلة تعطل لعبة Ender Magnolia (وغيرها من ألعاب UE). قد يؤدي إلى انخفاض في الأداء. يجري العمل على تحسينه.</string>
<string name="nce_runtime_nro_patch">تصحيح حالات NRO في وقت التشغيل لـ NCE</string>
<string name="nce_runtime_nro_patch_description">حل مؤقت. إصلاح مشكلة تشغيل لعبة Biomutant. قد يؤثر ذلك على الأداء. يجري العمل على تحسينه.</string>
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
<string name="emulate_bgr565">محاكاة BGR565</string>
@@ -579,8 +579,6 @@
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
<string name="nce_invalidation_gpu_readback">在 NCE 無效化前進行 GPU 回讀</string>
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
<string name="nce_runtime_nro_patch">對 NCE Runtime 的 NRO 檔案進行修補</string>
<string name="nce_runtime_nro_patch_description">(暫時性功能)修復 \"Biomutant\" 的啟動問題,可能會對效能造成影響。此功能正在改善中</string>
<string name="fix_bloom_effects">修正光暈特效</string>
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
<string name="emulate_bgr565">模擬 BGR565</string>
@@ -1197,4 +1195,4 @@
<!-- Licenses screen strings -->
<string name="licenses">授權</string>
<string name="license_fidelityfx_fsr_description">來自 AMD 的升級圖像品質</string>
</resources>
</resources>
@@ -595,8 +595,6 @@
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
<string name="nce_runtime_nro_patch">Patch Runtime NROs for NCE</string>
<string name="nce_runtime_nro_patch_description">Temporary. Fix Biomutant boot. May impact performance. Improvement in progress.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="emulate_bgr565">Emulate BGR565</string>
+3 -3
View File
@@ -256,7 +256,9 @@ struct Values {
CpuBackend::Dynarmic,
#endif
CpuBackend::Dynarmic,
#ifdef HAS_NCE
#if defined(HAS_SCARLETNX)
CpuBackend::ScarletNx,
#elif defined(HAS_NCE)
CpuBackend::Nce,
#else
CpuBackend::Dynarmic,
@@ -641,8 +643,6 @@ struct Values {
true};
SwitchableSetting<bool> nce_invalidation_gpu_readback{
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
SwitchableSetting<bool> nce_runtime_nro_patch{
linkage, false, "nce_runtime_nro_patch", Category::RendererHacks};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__
true,
+1 -1
View File
@@ -138,7 +138,7 @@ ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
ENUM(GpuAccuracy, Low, High);
ENUM(DmaAccuracy, Default, Unsafe, Safe);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate);
ENUM(CpuBackend, Dynarmic, Nce);
ENUM(CpuBackend, Dynarmic, Nce, ScarletNx);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
ENUM(CpuClock, Normal, Boost, Overclock)
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb, Memory_10Gb, Memory_12Gb);
+12
View File
@@ -1248,6 +1248,18 @@ if (HAS_NCE)
target_link_libraries(core PRIVATE merry::oaknut)
endif()
if (HAS_SCARLETNX)
target_sources(core PRIVATE
arm/scarletnx/arm_scarletnx_32.cpp
arm/scarletnx/arm_scarletnx_32.h
arm/scarletnx/arm_scarletnx_64.cpp
arm/scarletnx/arm_scarletnx_64.h
arm/scarletnx/scarletnx_api.h
arm/scarletnx/scarletnx_process.cpp
arm/scarletnx/scarletnx_process.h)
target_link_libraries(core PRIVATE ScarletNX::recompiler)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.h
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project */
/* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -5,9 +8,22 @@
#define __ASSEMBLY__
// Newer Linux UAPI headers check __ASSEMBLER__ instead of __ASSEMBLY__ to hide C declarations.
// Without it, asm-generic/signal.h redeclares sigset_t and clashes with glibc's. Only define it
// around these includes, since glibc headers also look at __ASSEMBLER__.
#ifndef __ASSEMBLER__
#define __ASSEMBLER__
#define EDEN_NCE_UNDEF_ASSEMBLER
#endif
#include <asm-generic/signal.h>
#include <asm-generic/unistd.h>
#ifdef EDEN_NCE_UNDEF_ASSEMBLER
#undef __ASSEMBLER__
#undef EDEN_NCE_UNDEF_ASSEMBLER
#endif
#define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2
#define BreakFromRunCodeSignal SIGURG
#define GuestAccessFaultSignal SIGSEGV
+42
View File
@@ -45,6 +45,23 @@ Patcher::Patcher() : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
WriteLoadContext(c_pre);
}
Patcher::Patcher(std::span<const u8> text) : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
modules.emplace_back();
curr_patch = &modules.back();
const auto words = std::span<const u32>{reinterpret_cast<const u32*>(text.data()), text.size() / sizeof(u32)};
for (u32 i = ModuleCodeIndex; i < static_cast<u32>(words.size()); ++i) {
const uintptr_t offset = i * sizeof(u32);
if (auto mrs = MRS{words[i]}; mrs.Verify() && mrs.GetRt() != 31 && (mrs.GetSystemReg() == TpidrEl0 || mrs.GetSystemReg() == TpidrroEl0)) {
BranchToPatch(offset);
const auto src_reg = mrs.GetSystemReg() == TpidrroEl0 ? oaknut::SystemReg::TPIDRRO_EL0 : oaknut::SystemReg::TPIDR_EL0;
WriteMrsHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(mrs.GetRt())}, src_reg);
} else if (auto msr = MSR{words[i]}; msr.Verify() && msr.GetSystemReg() == TpidrEl0) {
BranchToPatch(offset);
WriteMsrHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(msr.GetRt())});
}
}
}
Patcher::~Patcher() = default;
bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code) {
@@ -182,6 +199,31 @@ bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet
return true;
}
std::span<const u32> Patcher::RelocateRuntimeTls(
s64 patch_offset, std::vector<InstructionPatch>& out_patches) {
const auto& patch = modules.front();
const auto can_branch = [](s64 offset) {
return offset % 4 == 0 && offset >= -static_cast<s64>(MaxRelativeBranch) && offset < static_cast<s64>(MaxRelativeBranch);
};
out_patches.clear();
out_patches.reserve(patch.m_branch_to_patch_relocations.size());
for (const auto& rel : patch.m_branch_to_patch_relocations) {
const s64 offset = patch_offset + rel.patch_offset - static_cast<s64>(rel.module_offset);
if (!can_branch(offset)) {return {};}
u32 replacement;
oaknut::CodeGenerator rc{&replacement};
rc.B(offset);
out_patches.push_back({rel.module_offset, replacement});
}
for (const auto& rel : patch.m_branch_to_module_relocations) {
const s64 offset = static_cast<s64>(rel.module_offset) - patch_offset - rel.patch_offset;
if (!can_branch(offset)) {return {};}
oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)};
rc.B(offset);
}
return m_patch_instructions;
}
bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines) {
const size_t patch_size = GetSectionSize();
const size_t pre_patch_size = GetPreSectionSize();
+7
View File
@@ -48,15 +48,22 @@ using ModuleTextAddress = u64;
using PatchTextAddress = u64;
using EntryTrampolines = ::Common::unordered_map<ModuleTextAddress, PatchTextAddress>;
struct InstructionPatch {
u64 offset;
u32 replacement;
};
class Patcher {
public:
void SetModuleID(const ModuleID& id) {
module_id = id;
}
explicit Patcher();
explicit Patcher(std::span<const u8> text);
~Patcher();
bool PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code);
bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines);
std::span<const u32> RelocateRuntimeTls(s64 patch_offset, std::vector<InstructionPatch>& out_patches);
size_t GetSectionSize() const noexcept;
size_t GetPreSectionSize() const noexcept;
+227
View File
@@ -0,0 +1,227 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include <utility>
#include <atomic>
#include "common/logging.h"
#include "core/arm/scarletnx/arm_scarletnx_32.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_process.h"
namespace Core {
namespace {
// The exit SignalInterrupt sets, which no block sets itself.
constexpr u32 InterruptExit = 0x1000;
constexpr u32 UserMode = 0x10;
constexpr u32 ModeMask = 0x1F;
// FPSCR splits into FPSR and FPCR as in ArmDynarmic32.
std::pair<u32, u32> FpscrToFpsrFpcr(u32 fpscr) {
const u32 fpsr = (fpscr & 0xf8000000) | (fpscr & 0x80) | (fpscr & 0x1f);
const u32 fpcr = (fpscr & 0x7ff8000) | (fpscr & 0x1f00);
return {fpsr, fpcr};
}
u32 FpsrFpcrToFpscr(u64 fpsr, u64 fpcr) {
const auto [s, c] = FpscrToFpsrFpcr(u32(fpsr | fpcr));
return s | c;
}
} // namespace
ArmScarletNx32::ArmScarletNx32(std::shared_ptr<ScarletNxProcess> process, std::size_t core_index)
: ArmInterface{true}, m_process{std::move(process)}, m_core_index{core_index} {
m_rt.coproc = &Coprocessor;
m_cpu.parent = this;
m_cpu.cpu.mem = m_process->m_arena;
m_cpu.cpu.mem_size = 1ULL << 32;
m_cpu.cpu.rt = &m_rt;
m_fault_scope.memory = &m_process->m_process.GetMemory();
m_fault_scope.arena = m_process->m_arena;
m_fault_scope.arena_size = ScarletNxProcess::ArenaSize;
}
ArmScarletNx32::~ArmScarletNx32() {
snx_recompiled32_free(m_module);
}
int ArmScarletNx32::Svc(void* context, u32 imm, u64 number, const u64 arguments[6]) {
auto& self = *static_cast<ArmScarletNx32*>(context);
self.m_svc = imm;
self.m_in_svc = true;
return 1;
}
void ArmScarletNx32::Coprocessor(SnxArmCPU* cpu, u32 word) {
auto& self = *reinterpret_cast<Cpu32*>(cpu)->parent;
const u32 coproc = (word >> 8) & 0xF;
const u32 crm = word & 0xF;
if (coproc == 15 && (word & 0x0F100010) == 0x0E000010) {
// MCR p15
const u32 opc1 = (word >> 21) & 7;
const u32 crn = (word >> 16) & 0xF;
const u32 opc2 = (word >> 5) & 7;
if (opc1 == 0 && crn == 7 && crm == 5 && opc2 == 4) {
// CP15_FLUSH_PREFETCH_BUFFER
return;
}
if (opc1 == 0 && crn == 7 && crm == 10 && (opc2 == 4 || opc2 == 5)) {
// CP15_DATA_SYNC_BARRIER, CP15_DATA_MEMORY_BARRIER
std::atomic_thread_fence(std::memory_order_seq_cst);
return;
}
} else if (coproc == 15 && (word & 0x0FF00000) == 0x0C500000) {
// MRRC p15
const u32 opc1 = (word >> 4) & 0xF;
const u32 rt = (word >> 12) & 0xF;
const u32 rt2 = (word >> 16) & 0xF;
if (opc1 == 0 && crm == 14) {
// CNTPCT
const u64 ticks = self.m_process->m_system.CoreTiming().GetClockTicks();
cpu->r[rt] = u32(ticks);
cpu->r[rt2] = u32(ticks >> 32);
return;
}
}
// TPIDRURW and TPIDRURO, and undefined for anything else.
snx_arm_coproc_user(cpu, word);
ASSERT(cpu->exit == SNX_ARM_OK && "unhandled coproc");
}
HaltReason ArmScarletNx32::RunThread(Kernel::KThread* thread) {
if (m_interrupt.exchange(false)) {
return HaltReason::BreakLoop;
}
// The block cache only covers the code present when it was made.
const u64 generation = m_process->CodeGeneration();
if (!m_module || generation != m_code_generation) {
snx_recompiled32_free(m_module);
m_module = m_process->MakeModule32();
m_code_generation = generation;
}
LoadCpu();
m_in_svc = false;
m_fault_scope.last_fault = ~u64{};
SetScarletNxFaultScope(&m_fault_scope);
if (sigsetjmp(m_fault_scope.env, 1) != 0) {
SetScarletNxFaultScope(nullptr);
LOG_CRITICAL(Core_ARM, "invalid memory access at {:#x}",
m_fault_scope.fault_address);
SaveCpu();
return HaltReason::PrefetchAbort;
}
const int exit =
m_module ? snx_recompiled32_run(m_module, &m_cpu.cpu, &Svc, this) : SNX_ARM_BAD_ENTRY;
SetScarletNxFaultScope(nullptr);
SaveCpu();
return Halt(exit);
}
HaltReason ArmScarletNx32::Halt(int exit) {
if (m_in_svc) {
return HaltReason::SupervisorCall;
}
u32 const pc = m_cpu.cpu.r[15];
u32 const syndrome = m_cpu.cpu.syndrome;
switch (u32(exit)) {
case InterruptExit:
m_interrupt.store(false);
return HaltReason::BreakLoop;
case SNX_ARM_BREAKPOINT:
// As Dynarmic does without a debugger: report it and go on.
LOG_CRITICAL(Core_ARM, "BKPT #{:#x} at {:#x}", syndrome, pc);
return HaltReason::BreakLoop;
default:
LOG_CRITICAL(Core_ARM, "A32 exit {} at {:#x} (syndrome {:#x})", exit, pc, syndrome);
return HaltReason::PrefetchAbort;
}
}
HaltReason ArmScarletNx32::StepThread(Kernel::KThread* thread) {
// Never reached: the debugger selects Dynarmic.
LOG_ERROR(Core_ARM, "ScarletNX cannot single step");
return HaltReason::BreakLoop;
}
void ArmScarletNx32::LoadCpu() {
auto& cpu = m_cpu.cpu;
static_assert(sizeof(cpu.d) <= sizeof(m_ctx.v));
for (std::size_t i = 0; i < 16; i++)
cpu.r[i] = u32(m_ctx.r[i]);
cpu.cpsr = (m_ctx.pstate & ~ModeMask) | UserMode;
std::memcpy(cpu.d, m_ctx.v.data(), sizeof(cpu.d));
cpu.fpscr = FpsrFpcrToFpscr(m_ctx.fpsr, m_ctx.fpcr);
cpu.tpidrurw = u32(m_ctx.tpidr);
cpu.tpidruro = m_tpidrro;
cpu.exclusive_valid = 0;
}
void ArmScarletNx32::SaveCpu() {
const auto& cpu = m_cpu.cpu;
for (std::size_t i = 0; i < 16; i++)
m_ctx.r[i] = cpu.r[i];
m_ctx.fp = cpu.r[11];
m_ctx.sp = cpu.r[13];
m_ctx.lr = cpu.r[14];
m_ctx.pc = cpu.r[15];
m_ctx.pstate = cpu.cpsr;
std::memcpy(m_ctx.v.data(), cpu.d, sizeof(cpu.d));
const auto [fpsr, fpcr] = FpscrToFpsrFpcr(cpu.fpscr);
m_ctx.fpsr = fpsr;
m_ctx.fpcr = fpcr;
m_ctx.tpidr = cpu.tpidrurw;
}
void ArmScarletNx32::GetContext(Kernel::Svc::ThreadContext& ctx) const {
ctx = m_ctx;
}
void ArmScarletNx32::SetContext(const Kernel::Svc::ThreadContext& ctx) {
m_ctx = ctx;
}
void ArmScarletNx32::SetTpidrroEl0(u64 value) {
m_tpidrro = u32(value);
}
void ArmScarletNx32::GetSvcArguments(std::span<uint64_t, 8> args) const {
for (std::size_t i = 0; i < args.size(); i++)
args[i] = u32(m_ctx.r[i]);
}
void ArmScarletNx32::SetSvcArguments(std::span<const uint64_t, 8> args) {
for (std::size_t i = 0; i < args.size(); i++)
m_ctx.r[i] = u32(args[i]);
}
u32 ArmScarletNx32::GetSvcNumber() const {
return m_svc;
}
void ArmScarletNx32::SignalInterrupt(Kernel::KThread* thread) {
// The run loop checks the exit between blocks. A block's own exit takes precedence.
m_interrupt.store(true);
u32 expected = SNX_ARM_OK;
__atomic_compare_exchange_n(&m_cpu.cpu.exit, &expected, InterruptExit, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
}
void ArmScarletNx32::ClearInstructionCache() {
m_process->ClearInstructionCache();
}
void ArmScarletNx32::InvalidateCacheRange(u64 addr, std::size_t size) {
m_process->InvalidateCacheRange(addr, size);
}
} // namespace Core
+81
View File
@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <atomic>
#include <memory>
#include "core/arm/arm_interface.h"
#include "core/arm/scarletnx/scarletnx_api.h"
#include "core/arm/scarletnx/scarletnx_process.h"
namespace Core {
/// Runs A32 and Thumb code through ScarletNX's block compiler. Blocks return to the run loop, so
/// an SVC ends the run with r15 past it. The block cache is not thread-safe, so each core has its
/// own, rebuilt when the process' code changes.
class ArmScarletNx32 final : public ArmInterface {
public:
ArmScarletNx32(std::shared_ptr<ScarletNxProcess> process, std::size_t core_index);
~ArmScarletNx32() override;
Architecture GetArchitecture() const override {
return Architecture::AArch32;
}
HaltReason RunThread(Kernel::KThread* thread) override;
HaltReason StepThread(Kernel::KThread* thread) override;
void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
void SetTpidrroEl0(u64 value) override;
void GetSvcArguments(std::span<uint64_t, 8> args) const override;
void SetSvcArguments(std::span<const uint64_t, 8> args) override;
u32 GetSvcNumber() const override;
void SignalInterrupt(Kernel::KThread* thread) override;
void ClearInstructionCache() override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
protected:
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override {
return nullptr;
}
void RewindBreakpointInstruction() override {}
private:
// The CPU first, so the coprocessor hook can find its interface.
struct Cpu32 {
SnxArmCPU cpu;
ArmScarletNx32* parent;
};
static int Svc(void* context, u32 imm, u64 number, const u64 arguments[6]);
static void Coprocessor(SnxArmCPU* cpu, u32 word);
HaltReason Halt(int exit);
void LoadCpu();
void SaveCpu();
std::shared_ptr<ScarletNxProcess> m_process;
std::size_t m_core_index{};
snx_recompiled32* m_module{};
u64 m_code_generation{~u64{}};
// The context the kernel reads and writes; m_cpu holds it while guest code runs.
Kernel::Svc::ThreadContext m_ctx{};
u32 m_tpidrro{};
Cpu32 m_cpu{};
SnxArmRt m_rt{};
bool m_in_svc{};
u32 m_svc{};
std::atomic<bool> m_interrupt{};
ScarletNxFaultScope m_fault_scope{};
};
} // namespace Core
+261
View File
@@ -0,0 +1,261 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include <sys/mman.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging.h"
#include "core/arm/scarletnx/arm_scarletnx_64.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_process.h"
namespace Core {
namespace {
using namespace Common::Literals;
namespace ctx = boost::context::detail;
// Reserved, not committed: guest calls nest on it, and recompiling a region runs on it too.
constexpr std::size_t StackSize = 32_MiB;
constexpr std::size_t GuardSize = 64_KiB;
bool SameContext(const Kernel::Svc::ThreadContext a, const Kernel::Svc::ThreadContext b, bool in_svc) {
// An SVC returns its results in x0-x7.
for (std::size_t i = in_svc ? 8 : 0; i < a.r.size(); i++)
if (a.r[i] != b.r[i])
return false;
return a.fp == b.fp && a.lr == b.lr && a.sp == b.sp && a.pc == b.pc
&& (a.pstate >> 28) == (b.pstate >> 28) && a.v == b.v && a.fpcr == b.fpcr
&& a.fpsr == b.fpsr && a.tpidr == b.tpidr;
}
} // namespace
const RtAPI* ArmScarletNx64::Runtime() {
// this incurs a cost each time we call Runtime() -- but we only ever call it once (ideally)
static const RtAPI rt = [] {
RtAPI api;
snx_runtime_defaults(&api);
api.svc = &Svc;
api.undef = &Undefined;
api.brk = &Breakpoint;
api.poll = &Poll;
api.miss = &Miss;
api.code_changed = &CodeChanged;
api.ticks = &ScarletNxTicks;
return api;
}();
return &rt;
}
ArmScarletNx64::ArmScarletNx64(std::shared_ptr<ScarletNxProcess> process, std::size_t core_index)
: ArmInterface{true}
, m_process{std::move(process)}, m_core_index{core_index}
{
// can't use virtualbuffer...
void* const stack = mmap(nullptr, StackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_MSG(stack != MAP_FAILED, "cannot allocate a guest stack");
m_stack = static_cast<u8*>(stack);
mprotect(m_stack, GuardSize, PROT_NONE);
m_cpu.mem = m_process->m_arena;
m_cpu.rt = Runtime();
m_cpu.thread = this;
m_fault_scope.memory = &m_process->m_process.GetMemory();
m_fault_scope.arena = m_process->m_arena;
m_fault_scope.arena_size = ScarletNxProcess::ArenaSize;
}
ArmScarletNx64::~ArmScarletNx64() {
munmap(m_stack, StackSize);
}
void ArmScarletNx64::Svc(CPU* cpu, u32 imm) {
auto& self = From(cpu);
self.m_svc = imm;
self.Yield(HaltReason::SupervisorCall, true, true);
}
void ArmScarletNx64::Undefined(CPU* cpu, u64 pc, u32 word) {
// A reserved encoding rejected from inside an instruction, which then goes on.
if (cpu->pc != pc) {
LOG_ERROR(Core_ARM, "reserved encoding {:08X} at {:#x}", word, pc);
return;
}
LOG_CRITICAL(Core_ARM, "cannot execute {:08X} at {:#x}", word, pc);
From(cpu).Yield(HaltReason::PrefetchAbort, false, false);
UNREACHABLE();
}
void ArmScarletNx64::Breakpoint(CPU* cpu, u64 pc, u32 imm) {
// As Dynarmic does without a debugger: report it and go on.
LOG_CRITICAL(Core_ARM, "BRK #{:#x} at {:#x}", imm, pc);
cpu->pc = pc + 4;
}
void ArmScarletNx64::Poll(CPU* cpu) {
auto& self = From(cpu);
__atomic_store_n(&cpu->poll, 0, __ATOMIC_RELAXED);
if (self.m_interrupt.exchange(false))
self.Yield(HaltReason::BreakLoop, true, false);
}
void ArmScarletNx64::Miss(CPU* cpu, u64 pc) {
auto& process = *From(cpu).m_process;
const auto function = process.Lookup(pc);
if (!function) {
cpu->pc = pc;
Undefined(cpu, pc, 0);
return;
}
// The first region was recompiled by this lookup: dispatch through its table from now on.
if (snx_recompiled* const module = cpu->disp ? nullptr : process.FindModule(pc))
snx_recompiled_bind(module, cpu);
function(cpu, pc);
}
void ArmScarletNx64::CodeChanged(CPU* cpu, u64 addr) {
constexpr u64 ICacheLineSize = 64;
From(cpu).m_process->InvalidateCacheRange(addr & ~(ICacheLineSize - 1), ICacheLineSize);
}
void ArmScarletNx64::Entry(ctx::transfer_t transfer) {
auto* const self = static_cast<ArmScarletNx64*>(transfer.data);
self->m_host = transfer.fctx;
self->Execute();
}
void ArmScarletNx64::Execute() {
if (sigsetjmp(m_fault_scope.env, 1) != 0) {
LOG_CRITICAL(Core_ARM, "invalid memory access at {:#x}", m_fault_scope.fault_address);
Yield(HaltReason::PrefetchAbort, false, false);
UNREACHABLE();
}
// Every guest return to below the first frame comes back here.
while (true)
snx_lookup(&m_cpu, m_cpu.pc)(&m_cpu, m_cpu.pc);
}
void ArmScarletNx64::Yield(HaltReason reason, bool resumable, bool in_svc) {
m_halt = reason;
m_resumable = resumable;
m_suspended_in_svc = in_svc;
m_host = ctx::jump_fcontext(m_host, nullptr).fctx;
}
void ArmScarletNx64::ResetGuest() {
m_guest = ctx::make_fcontext(m_stack + StackSize, StackSize - GuardSize, &Entry);
if (snx_recompiled* const module = m_process->FindModule(m_cpu.pc))
snx_recompiled_bind(module, &m_cpu);
}
HaltReason ArmScarletNx64::RunThread(Kernel::KThread* thread) {
if (m_interrupt.exchange(false))
return HaltReason::BreakLoop;
bool const resume = m_resumable && m_suspended_thread_id == thread->GetThreadId() && SameContext(m_ctx, m_suspended_ctx, m_suspended_in_svc);
LoadCpu();
if (!resume)
ResetGuest();
m_resumable = false;
m_fault_scope.last_fault = ~u64{};
SetScarletNxFaultScope(&m_fault_scope);
m_guest = ctx::jump_fcontext(m_guest, this).fctx;
SetScarletNxFaultScope(nullptr);
SaveCpu();
if (m_resumable) {
m_suspended_thread_id = thread->GetThreadId();
m_suspended_ctx = m_ctx;
}
return m_halt;
}
HaltReason ArmScarletNx64::StepThread(Kernel::KThread* thread) {
// Never reached: the debugger selects Dynarmic.
LOG_ERROR(Core_ARM, "ScarletNX cannot single step");
return HaltReason::BreakLoop;
}
void ArmScarletNx64::LoadCpu() {
static_assert(sizeof(m_cpu.v) == sizeof(m_ctx.v));
for (std::size_t i = 0; i < m_ctx.r.size(); i++)
m_cpu.x[i] = m_ctx.r[i];
m_cpu.x[29] = m_ctx.fp;
m_cpu.x[30] = m_ctx.lr;
m_cpu.x[31] = m_ctx.sp;
m_cpu.pc = m_ctx.pc;
set_nzcv(&m_cpu, m_ctx.pstate >> 28);
std::memcpy(m_cpu.v, m_ctx.v.data(), sizeof(m_cpu.v));
m_cpu.fpcr = m_ctx.fpcr;
m_cpu.fpsr = m_ctx.fpsr;
m_cpu.tpidr = m_ctx.tpidr;
m_cpu.tpidrro = m_tpidrro;
m_cpu.excl_on = 0;
}
void ArmScarletNx64::SaveCpu() {
for (std::size_t i = 0; i < m_ctx.r.size(); i++) {
m_ctx.r[i] = m_cpu.x[i];
}
m_ctx.fp = m_cpu.x[29];
m_ctx.lr = m_cpu.x[30];
m_ctx.sp = m_cpu.x[31];
m_ctx.pc = m_cpu.pc;
m_ctx.pstate = get_nzcv(&m_cpu);
std::memcpy(m_ctx.v.data(), m_cpu.v, sizeof(m_cpu.v));
m_ctx.fpcr = m_cpu.fpcr;
m_ctx.fpsr = m_cpu.fpsr;
m_ctx.tpidr = m_cpu.tpidr;
}
void ArmScarletNx64::GetContext(Kernel::Svc::ThreadContext& ctx) const {
ctx = m_ctx;
}
void ArmScarletNx64::SetContext(const Kernel::Svc::ThreadContext& ctx) {
m_ctx = ctx;
}
void ArmScarletNx64::SetTpidrroEl0(u64 value) {
m_tpidrro = value;
}
void ArmScarletNx64::GetSvcArguments(std::span<uint64_t, 8> args) const {
for (std::size_t i = 0; i < args.size(); i++) {
args[i] = m_ctx.r[i];
}
}
void ArmScarletNx64::SetSvcArguments(std::span<const uint64_t, 8> args) {
for (std::size_t i = 0; i < args.size(); i++) {
m_ctx.r[i] = args[i];
}
}
u32 ArmScarletNx64::GetSvcNumber() const {
return m_svc;
}
void ArmScarletNx64::SignalInterrupt(Kernel::KThread* thread) {
// Generated code reads poll on backward branches and calls Poll, which yields.
m_interrupt.store(true);
__atomic_store_n(&m_cpu.poll, 1, __ATOMIC_RELAXED);
}
void ArmScarletNx64::ClearInstructionCache() {
m_process->ClearInstructionCache();
}
void ArmScarletNx64::InvalidateCacheRange(u64 addr, std::size_t size) {
m_process->InvalidateCacheRange(addr, size);
}
} // namespace Core
+100
View File
@@ -0,0 +1,100 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <atomic>
#include <memory>
#include <boost/context/detail/fcontext.hpp>
#include "core/arm/arm_interface.h"
#include "core/arm/scarletnx/scarletnx_api.h"
#include "core/arm/scarletnx/scarletnx_process.h"
namespace Core {
/// Runs A64 code recompiled by ScarletNX.
///
/// A recompiled guest function is a host function that returns when the guest function returns,
/// so guest calls nest on the host stack and an SVC cannot return from the generated code. Guest
/// code therefore runs on a coroutine of this core, which the SVC and interrupt hooks suspend.
/// When the kernel next runs the same thread with the same context, the coroutine resumes;
/// otherwise its host frames are dropped and execution restarts at the new pc through dispatch.
class ArmScarletNx64 final : public ArmInterface {
public:
ArmScarletNx64(std::shared_ptr<ScarletNxProcess> process, std::size_t core_index);
~ArmScarletNx64() override;
Architecture GetArchitecture() const override {
return Architecture::AArch64;
}
HaltReason RunThread(Kernel::KThread* thread) override;
HaltReason StepThread(Kernel::KThread* thread) override;
void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
void SetTpidrroEl0(u64 value) override;
void GetSvcArguments(std::span<uint64_t, 8> args) const override;
void SetSvcArguments(std::span<const uint64_t, 8> args) override;
u32 GetSvcNumber() const override;
void SignalInterrupt(Kernel::KThread* thread) override;
void ClearInstructionCache() override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
protected:
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override {
return nullptr;
}
void RewindBreakpointInstruction() override {}
private:
static ArmScarletNx64& From(CPU* cpu) {
return *static_cast<ArmScarletNx64*>(cpu->thread);
}
static const RtAPI* Runtime();
// Runtime hooks called by the generated code.
static void Svc(CPU* cpu, u32 imm);
static void Undefined(CPU* cpu, u64 pc, u32 word);
static void Breakpoint(CPU* cpu, u64 pc, u32 imm);
static void Poll(CPU* cpu);
static void Miss(CPU* cpu, u64 pc);
static void CodeChanged(CPU* cpu, u64 addr);
static void Entry(boost::context::detail::transfer_t transfer);
[[noreturn]] void Execute();
void Yield(HaltReason reason, bool resumable, bool in_svc);
void ResetGuest();
void LoadCpu();
void SaveCpu();
std::shared_ptr<ScarletNxProcess> m_process;
std::size_t m_core_index{};
// The context the kernel reads and writes; m_cpu holds it while guest code runs.
Kernel::Svc::ThreadContext m_ctx{};
u64 m_tpidrro{};
CPU m_cpu{};
HaltReason m_halt{};
u32 m_svc{};
std::atomic<bool> m_interrupt{};
// The coroutine, and what it was suspended in, when it can be resumed.
boost::context::detail::fcontext_t m_guest{};
boost::context::detail::fcontext_t m_host{};
u8* m_stack{};
bool m_resumable{};
bool m_suspended_in_svc{};
u64 m_suspended_thread_id{};
Kernel::Svc::ThreadContext m_suspended_ctx{};
ScarletNxFaultScope m_fault_scope{};
};
} // namespace Core
+10
View File
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
// snx_recompiler.h includes cpu.h and arm.h before its own extern "C" block, so the whole
// header needs C linkage for the runtime library's functions to resolve.
extern "C" {
#include <scarletnx/snx_recompiler.h>
}
@@ -0,0 +1,300 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include <mutex>
#include <signal.h>
#include "common/fs/path_util.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/arm/scarletnx/arm_scarletnx_32.h"
#include "core/arm/scarletnx/arm_scarletnx_64.h"
#include "core/arm/scarletnx/scarletnx_api.h"
#include "core/arm/scarletnx/scarletnx_process.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/memory.h"
namespace Core {
namespace {
// ScarletNX refuses dispatch tables spanning more than 1 GiB of guest code.
constexpr u64 MaxModuleSpan = 1ULL << 30;
constexpr u64 A32Limit = 1ULL << 32;
std::atomic<Timing::CoreTiming*> g_core_timing{};
// Needs be TLS because SNX expects like, more than 4 threads (host == guest threads)
// and well -- quite impervious to "emulated" threads... maybe one day this can be removed
thread_local ScarletNxFaultScope* g_fault_scope{};
static struct {
struct sigaction old_sigsegv;
struct sigaction old_sigbus;
std::once_flag installed;
} g_snx_data;
bool Overlaps(const ScarletNxProcess::CodeRange& range, u64 addr, u64 size) {
return addr < range.addr + range.size && range.addr < addr + size;
}
void ChainSignal(int sig, siginfo_t* info, void* raw_context) {
const struct sigaction& old = sig == SIGSEGV ? g_snx_data.old_sigsegv : g_snx_data.old_sigbus;
if (old.sa_flags & SA_SIGINFO) {
old.sa_sigaction(sig, info, raw_context);
} else if (old.sa_handler == SIG_DFL) {
// The faulting instruction runs again and takes the default action.
signal(sig, SIG_DFL);
} else if (old.sa_handler != SIG_IGN) {
old.sa_handler(sig);
}
}
void FaultHandler(int sig, siginfo_t* info, void* raw_context) {
ScarletNxFaultScope* const scope = g_fault_scope;
u8* const addr = static_cast<u8*>(info->si_addr);
if (!scope || addr < scope->arena || addr >= scope->arena + scope->arena_size) {
ChainSignal(sig, info, raw_context);
return;
}
// Pages the rasterizer protects fault on access: invalidate them and retry. A second fault at
// the same addr means retrying will not help.
const u64 guest_address = u64(addr - scope->arena);
if (guest_address != scope->last_fault) {
scope->last_fault = guest_address;
if (scope->memory->InvalidateNCE(guest_address & ~Memory::YUZU_PAGEMASK, Memory::YUZU_PAGESIZE)) {
return;
}
}
scope->fault_address = guest_address;
siglongjmp(scope->env, 1);
}
} // namespace
void InstallScarletNxFaultHandler() {
std::call_once(g_snx_data.installed, [] {
struct sigaction action {};
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = &FaultHandler;
sigemptyset(&action.sa_mask);
sigaction(SIGSEGV, &action, &g_snx_data.old_sigsegv);
sigaction(SIGBUS, &action, &g_snx_data.old_sigbus);
});
}
void SetScarletNxFaultScope(ScarletNxFaultScope* scope) {
g_fault_scope = scope;
}
u64 ScarletNxTicks() {
return g_core_timing.load(std::memory_order_relaxed)->GetClockTicks();
}
std::unique_ptr<ArmInterface> MakeScarletNxInterface(std::shared_ptr<ScarletNxProcess> process, bool is_64bit, std::size_t core_index) {
if (is_64bit)
return std::make_unique<ArmScarletNx64>(std::move(process), core_index);
return std::make_unique<ArmScarletNx32>(std::move(process), core_index);
}
ScarletNxProcess::ScarletNxProcess(System& system, Kernel::KProcess& process)
: m_system{system}
, m_process{process}
, m_arena{system.DeviceMemory().buffer.VirtualBasePointer()}
{
InstallScarletNxFaultHandler();
g_core_timing.store(&system.CoreTiming(), std::memory_order_relaxed);
m_recompiler = snx_recompiler_new(SNX_RECOMPILER_FLAG_LLVM);
ASSERT(m_recompiler && "cannot create the recompiler");
// Linked modules are kept by a hash of their code, so later launches skip the recompile.
const auto cache = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "scarletnx";
if (snx_recompiler_set_cache(m_recompiler, Common::FS::PathToUTF8String(cache).c_str()) != 0)
LOG_WARNING(Core_ARM, "no code cache: {}", snx_recompiler_error(m_recompiler));
}
ScarletNxProcess::~ScarletNxProcess() {
for (auto& mod : m_modules)
snx_recompiled_free(mod.mod);
snx_recompiler_free(m_recompiler);
}
bool ScarletNxProcess::ShouldUse(System& system, const Kernel::KProcess& process) {
if (Settings::values.cpu_backend.GetValue() != Settings::CpuBackend::ScarletNx)
return false;
auto const f = [](auto& s) {
LOG_WARNING(Core_ARM, "snx: {}", s);
return false;
};
if (!process.IsApplication())
return f("no qlaunch yet");
if (!system.Kernel().IsMulticore())
return f("single core mode needs cycle counting");
if (system.DebuggerEnabled())
return f("the debugger needs stepping and watchpoints");
/// ScarletNX expects flat memory, so it will only work with fastmem
if (!Settings::IsFastmemEnabled() || !system.DeviceMemory().buffer.VirtualBasePointer())
return f("guest memory must be mapped by fastmem");
if (snx_recompiler_abi() != SNX_ABI)
return f("the library was built with a different ABI");
if (!snx_recompiler_has(SNX_RECOMPILER_FLAG_LLVM))
return f("LLVM cannot target this host");
return true;
}
std::vector<ScarletNxProcess::CodeRange> ScarletNxProcess::GetCodeRanges() const {
std::vector<CodeRange> r;
const auto& page_table = m_process.GetPageTable().GetBasePageTable();
u64 addr = GetInteger(page_table.GetAddressSpaceStart());
while (true) {
Kernel::KMemoryInfo info;
Kernel::Svc::PageInfo page_info;
if (page_table.QueryInfo(&info, &page_info, addr).IsError())
break;
if (True(info.GetPermission() & Kernel::KMemoryPermission::UserExecute)) {
if (!r.empty() && r.back().addr + r.back().size == info.GetAddress()) {
r.back().size += info.GetSize();
} else {
r.push_back({info.GetAddress(), info.GetSize()});
}
}
// The block past the addr space ends at 0.
if (info.GetEndAddress() <= addr)
break;
addr = info.GetEndAddress();
}
return r;
}
const ScarletNxProcess::Module* ScarletNxProcess::FindModuleLocked(u64 pc) const {
for (const auto& mod : m_modules) {
if (mod.retired || pc < mod.lo || pc >= mod.hi)
continue;
for (const auto& range : mod.ranges)
if (pc >= range.addr && pc < range.addr + range.size)
return &mod;
}
return nullptr;
}
snx_recompiled* ScarletNxProcess::RecompileRegionLocked(u64 pc) {
const auto r = GetCodeRanges();
const auto it = std::ranges::find_if(r, [pc](const CodeRange& range) {
return pc >= range.addr && pc < range.addr + range.size;
});
if (it == r.end())
return nullptr;
const auto is_covered = [this](const CodeRange& range) {
return std::ranges::any_of(m_modules, [&](const Module& mod) {
return !mod.retired && std::ranges::any_of(mod.ranges, [&](const CodeRange& cr) {
return Overlaps(cr, range.addr, range.size);
});
});
};
// Recompile as many neighbouring regions as one dispatch table can cover.
auto first = size_t(it - r.begin());
auto last = first;
const auto end_of = [&](size_t i) { return r[i].addr + r[i].size; };
while (first > 0 && !is_covered(r[first - 1]) && end_of(last) - r[first - 1].addr <= MaxModuleSpan)
--first;
while (last + 1 < r.size() && !is_covered(r[last + 1])
&& end_of(last + 1) - r[first].addr <= MaxModuleSpan)
++last;
Module mod{};
mod.ranges.assign(r.begin() + first, r.begin() + last + 1);
mod.lo = r[first].addr;
mod.hi = end_of(last);
std::vector<snx_code_range> code;
u64 code_size = 0;
for (const auto& range : mod.ranges) {
code.push_back({range.addr, m_arena + range.addr, range.size});
code_size += range.size;
}
LOG_INFO(Core_ARM, "recompiling {} KiB of code at {:#x}-{:#x}", code_size / 1024, mod.lo, mod.hi);
mod.mod = snx_recompile_ranges(m_recompiler, code.data(), code.size(), &pc, 1);
if (mod.mod) {
LOG_INFO(Core_ARM, "recompiled {} functions", snx_recompiled_functions(mod.mod));
} else {
// Kept, so the region is not recompiled again on every miss.
LOG_ERROR(Core_ARM, "recompilation failed: {}", snx_recompiler_error(m_recompiler));
}
m_modules.push_back(std::move(mod));
return m_modules.back().mod;
}
ScarletNxProcess::SnxGuestFn ScarletNxProcess::Lookup(u64 pc) {
snx_recompiled* mod;
{
std::scoped_lock lk{m_mutex};
const Module* const known = FindModuleLocked(pc);
mod = known ? known->mod : RecompileRegionLocked(pc);
}
if (!mod)
return nullptr;
// Waits for the mod's JIT when discovery missed the code at pc.
return snx_recompiled_lookup(mod, pc);
}
snx_recompiled* ScarletNxProcess::FindModule(u64 pc) {
std::scoped_lock lk{m_mutex};
const Module* const mod = FindModuleLocked(pc);
return mod ? mod->mod : nullptr;
}
snx_recompiled32* ScarletNxProcess::MakeModule32() {
std::scoped_lock lk{m_mutex};
std::vector<snx_code_range> code;
for (const auto& range : GetCodeRanges()) {
if (range.addr >= A32Limit) {
continue;
}
code.push_back({range.addr, nullptr, std::min(range.size, A32Limit - range.addr)});
}
if (code.empty())
return nullptr;
snx_recompiled32* const mod = snx_recompile32_ranges(m_recompiler, code.data(), code.size());
if (!mod)
LOG_ERROR(Core_ARM, "cannot prepare A32 code: {}", snx_recompiler_error(m_recompiler));
return mod;
}
void ScarletNxProcess::InvalidateCacheRange(u64 addr, u64 size) {
std::scoped_lock lk{m_mutex};
for (auto& mod : m_modules) {
if (mod.retired || !std::ranges::any_of(mod.ranges, [&](const CodeRange& range) {
return Overlaps(range, addr, size);
}))
continue;
// Running code diverts out of the retired functions, and the region is recompiled from
// the new code when it is next reached.
if (mod.mod)
snx_recompiled_invalidate(mod.mod, addr, size, nullptr, nullptr);
mod.retired = true;
}
m_code_generation.fetch_add(1, std::memory_order_release);
}
void ScarletNxProcess::ClearInstructionCache() {
std::scoped_lock lk{m_mutex};
for (auto& mod : m_modules) {
if (!mod.retired && mod.mod)
snx_recompiled_invalidate(mod.mod, mod.lo, mod.hi - mod.lo, nullptr, nullptr);
mod.retired = true;
}
m_code_generation.fetch_add(1, std::memory_order_release);
}
} // namespace Core
+104
View File
@@ -0,0 +1,104 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <atomic>
#include <csetjmp>
#include <memory>
#include <mutex>
#include <vector>
#include "common/common_types.h"
struct CPU;
struct snx_recompiler;
struct snx_recompiled;
struct snx_recompiled32;
namespace Kernel {
class KProcess;
}
namespace Core::Memory {
class Memory;
}
namespace Core {
class ArmInterface;
class System;
class ScarletNxProcess {
public:
using SnxGuestFn = void (*)(CPU*, u64);
// DeviceMemory reserves 39 bits of address space for the fastmem arena.
static constexpr u64 ArenaSize = 1ULL << 39;
struct CodeRange {
u64 addr;
u64 size;
};
ScarletNxProcess(System& system, Kernel::KProcess& process);
~ScarletNxProcess();
static bool ShouldUse(System& system, const Kernel::KProcess& process);
SnxGuestFn Lookup(u64 pc);
snx_recompiled* FindModule(u64 pc);
snx_recompiled32* MakeModule32();
void InvalidateCacheRange(u64 addr, u64 size);
void ClearInstructionCache();
/// @brief general gate for when we are about to invalidate a given block aka. trigger regen
u64 CodeGeneration() const {
return m_code_generation.load(std::memory_order_acquire);
}
struct Module {
std::vector<CodeRange> ranges;
u64 lo;
u64 hi;
snx_recompiled* mod;
bool retired;
};
std::vector<CodeRange> GetCodeRanges() const;
const Module* FindModuleLocked(u64 pc) const;
snx_recompiled* RecompileRegionLocked(u64 pc);
std::vector<Module> m_modules;
std::atomic<u64> m_code_generation{};
// TODO: remove parent ref?
System& m_system;
Kernel::KProcess& m_process;
u8* m_arena{};
snx_recompiler* m_recompiler{};
// ScarletNX's recompiler is used by one thread at a time.
std::mutex m_mutex;
};
/// Recovers from host faults in guest memory on the thread running guest code: a fault on a
/// page the rasterizer protects is resolved and retried, any other jumps to env.
struct ScarletNxFaultScope {
sigjmp_buf env;
Memory::Memory* memory{};
u8* arena{};
u64 arena_size{};
u64 last_fault{~0ull};
u64 fault_address{};
};
void InstallScarletNxFaultHandler();
void SetScarletNxFaultScope(ScarletNxFaultScope* scope);
/// CNTPCT_EL0 of the emulated system.
u64 ScarletNxTicks();
std::unique_ptr<ArmInterface> MakeScarletNxInterface(std::shared_ptr<ScarletNxProcess> process, bool is_64bit, std::size_t core_index);
} // namespace Core
+10
View File
@@ -23,6 +23,9 @@
#ifdef HAS_NCE
#include "core/arm/nce/arm_nce.h"
#endif
#ifdef HAS_SCARLETNX
#include "core/arm/scarletnx/scarletnx_process.h"
#endif
namespace Kernel {
@@ -1311,6 +1314,13 @@ void KProcess::InitializeInterfaces(KernelCore& kernel) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++)
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(kernel.System(), true, i);
} else
#endif
#ifdef HAS_SCARLETNX
if (Core::ScarletNxProcess::ShouldUse(kernel.System(), *this)) {
auto scarletnx = std::make_shared<Core::ScarletNxProcess>(kernel.System(), *this);
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++)
m_arm_interfaces[i] = Core::MakeScarletNxInterface(scarletnx, this->Is64Bit(), i);
} else
#endif
if (this->Is64Bit()) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+1 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
+1 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/service/common_state_getter.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,7 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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

Some files were not shown because too many files have changed in this diff Show More