# Game-specific patches

Every piece of code that runs for one game and not the others: the rewriter's patches of a game's builds (`dm/games/<id>/patches.py`, keyed by NSO build ID: [rewriter](../reference/rewriter.md)), the host's rows keyed by a game's build ID, the SDK cuts of the Nintendo SDK builds the games ship, translator rules keyed by one shader's code, and the profile keys that switch host behaviour. Each patch's reason is the one in its source; why it is needed, and what was measured, is in the game's note. Each patch states its binding: what it depends on now, the loosest it could depend on (its goal), its purpose and why ([Binding](#binding)); the [gaps](#gaps) are the work list. Offsets are from the module's start. Generated by `dm/tools/docs_patches.py` from those sources (a patch file's `BINDING`; the host rows', translator rules' and profile switches' entries in `docs_patches.py`): change the source, then run it.

## Binding

A patch's binding is what its correctness is anchored to, from the loosest. A patch is good design when its binding is the loosest that is correct (AGENTS.md prefers general fixes); the rules are in GitHub issue #635.

| Binding | Anchored to | Found by | Survives |
|---|---|---|---|
| `host` | Horizon / NVN / Vulkan semantics | nothing in the binary | every game and update |
| `sdk` | Nintendo SDK code (the `sdk` module) | a symbol, or a fingerprint of a reviewed SDK implementation | any game shipping that implementation |
| `engine` | middleware code: Unreal, Unity, Snowdrop, KTGL, sead, PhysX | a registered name, a string, or a fingerprint per engine version | any game on that engine version |
| `game` | the game's own code, or its profile's data | a function fingerprint (`MATCH_CUTS`), or a profile key | the game's updates that keep the function |
| `build` | fixed offsets | the NSO build ID | nothing: redone for every update |

- Status: **at goal** (the binding now is the goal), **gap** (it could be looser: the work list), **blocked** (a gap with the reason it cannot close yet), **kept** (a gap left open on purpose, with the decision) or **unreviewed** (a game's own build-bound patch whose goal nobody has judged yet, which a bring-up may leave rather than guess).
- Locators fail closed: a patch that finds its place in the binary (a function fingerprint, a registered name, a string) applies only where it finds exactly one match with its assumptions checked, and changes nothing otherwise, with a red line where it was expected to match (a profile's own `MATCH_CUTS`, a host search) and a plain one where a module may not need it (an SDK-wide rule). That is what makes a looser binding safe on builds nobody has seen ([function-matched cuts](../reference/rewriter.md#function-matched-cuts-for-unregistered-builds)).
- Evidence: **checked** (what was checked on game files, and when) or **judgement** (the goal is reasoned from the code and notes, not checked on game files).
- Purposes: address space, memory, race, frame rate, power, rendering, shaders, runtime.

## Gaps

Every patch bound tighter than it could be: the open gaps, then the blocked, kept and unreviewed ones; in each, those reaching the most games first (the games whose profiles register the builds it touches), then those farthest from their goal.

| Now → goal | Patch | Purpose | Status | Evidence | Games | Where | Why |
|---|---|---|---|---|---|---|---|
| `build` → `game` | 60 fps intervals and dynamic-resolution constants | frame rate | gap | checked: both releases' mains, where the host's rows for them were found | 2 | [NieR:Automata The End of YoRHa Edition (010056B015FE8000)](../../dm/games/010056B015FE8000/README.md); [NieR:Automata The End of YoRHa Edition (0100B8E016F76000)](../../dm/games/0100B8E016F76000/README.md) | the game's own constants; the Asian release's function is the global one's 0x13c0 further on, so one function-matched rule could serve both releases |
| `build` → `game` | NieR's frame interval and dynamic-resolution floor at fixed addresses | frame rate | gap | checked: both releases' mains, where these rows were found | 2 | [NieR:Automata The End of YoRHa Edition (010056B015FE8000)](../../dm/games/010056B015FE8000/README.md); [NieR:Automata The End of YoRHa Edition (0100B8E016F76000)](../../dm/games/0100B8E016F76000/README.md) | the game's own display object; the Asian release's function is the global one's 0x13c0 further on, so the rewriter's function match could give the host both releases' addresses |
| `build` → `host` | frame limiter wait: yield → sleep | power | gap | checked: Mac runs with the cut undone, 2026-10-26 (the game note) | 1 | [Fire Emblem: Three Houses](../../dm/games/010055D009F78000/README.md) | without it the host's yield back-off (thr_yield) holds 59.7 to 59.8 fps, at 0.9 to 1.2 W of CPU against 0.14 to 0.42 W (2026-10-26): a back-off that reaches a yield-and-tick loop's deadline sooner would make the cut unnecessary for every game |
| `game` → `host` | one vertex shader's visibility counter (VertexCounterLowering) | shaders | gap | judgement | — | [Program.cs:259](../../dm/gfx/tools/dmsh_xlate/Program.cs#L259) | a general lowering of subgroup ballots in vertex shaders would cover any shader that counts that way |
| `build` → `engine` | Unity QualitySettings.vSyncCount held at 1 | frame rate | gap | judgement | 1 | [Fire Emblem Engage](../../dm/games/0100A6301214E000/README.md) | an IL2CPP player registers the setter by its icall name, so the place can be found in any Unity game; holding it at 1 stays this profile's choice (its logic steps by the count) |
| `build` → `engine` | Unity's Application.targetFrameRate at a fixed address | frame rate | gap | judgement | 1 | [Pokémon Brilliant Diamond](../../dm/games/0100000011D90000/README.md) | an IL2CPP player registers the setter by its icall name, so the field can be found in any Unity game; whether to raise it stays the profile's |
| `build` → `game` | frame limiter 30 → 60 fps and the 1/60 update step | frame rate | gap | judgement | 1 | [DARK SOULS: REMASTERED](../../dm/games/01004AB00A260000/README.md) | the game's own limiter constant and fixed step |
| `build` → `game` | frame limiter spin: its branch back cut | frame rate | gap | judgement | 1 | [Need For Speed™ Hot Pursuit Remastered](../../dm/games/010029B0118E8000/README.md) | the engine's own spin limiter; a function-matched rule could carry it over the game's updates |
| `build` → `game` | frame step floor 2 → 1 vsync, and its frame step | frame rate | gap | judgement | 1 | [Paper Mario: The Thousand-Year Door](../../dm/games/0100ECD018EBE000/README.md) | the game's own clock floor and step; MATCH_CUTS and MATCH_FRAME_STEP could carry the cut and the stub, both near the step's function (main+0x2e7750; one function not checked yet) |
| `build` → `game` | interval controller: the lower bound and the GPU-time path | frame rate | gap | judgement | 1 | [The Legend of Zelda: Breath of the Wild](../../dm/games/01007EF00011E000/README.md) | sead::GameFrameworkNx's interval controller in this build; Tears of the Kingdom shares sead but not this code |
| `build` → `game` | job pool wake-up | race | gap | judgement | 1 | [FINAL FANTASY TACTICS - The Ivalice Chronicles](../../dm/games/010038B015560000/README.md) | a lost wake-up in the game's own job pool, not a host or SDK difference |
| `build` → `game` | malloc region 60 GB → 4 GB and its first arena | address space | gap | judgement | 1 | [Xenoblade Chronicles 3](../../dm/games/010074F013262000/README.md) | Monolith's own allocator; its constants span two functions (a multi-function rule). The cause, an iPhone's address space, is a platform limit |
| `build` → `game` | PhysX completion task release | race | gap | judgement | 1 | [The Legend of Zelda: Link's Awakening](../../dm/games/01006BB00C6F0000/README.md) | a lifetime race in the game's own completion task (its release slot serves this one vtable) |
| `build` → `game` | render intervals, the forced-interval flag and the render-wait timeout | frame rate | gap | judgement | 1 | [Fire Emblem: Three Houses](../../dm/games/010055D009F78000/README.md) | the game's own tables, flag and timeout |
| `build` → `game` | task ring push and pop barriers | race | gap | judgement | 1 | [Batman: Arkham Knight](../../dm/games/0100ACD0163D0000/README.md) | a data race in the game's own task ring |
| `build` → `game` | UE3's GMalloc setup skipped, the host allocator in (hle_uemalloc.c) | address space | gap | judgement | 1 | [Batman: Arkham Knight](../../dm/games/0100ACD0163D0000/README.md) | UE3 inlines the allocator's constructor into the GMalloc setup and has its own vtable layout (25 slots, 32-bit sizes), so the Unreal 4/5 discovery does not apply |
| `build` → `game` | unused 272-byte slot pool: 4,194,304 → 65,536 slots | address space | gap | judgement | 1 | [Mario + Rabbids® Sparks of Hope](../../dm/games/0100317013770000/README.md) | Sparks of Hope's own init (Kingdom Battle has none) |
| `build` → `sdk` | rows the rules would add the alignment cuts to (2d369d99, 12f16103, 311deab1) | address space | blocked: the games that reach them (Pokémon Brilliant Diamond, Monster Hunter Rise, 13 Sentinels: Aegis Rim; Brain Memory Training Academy; Ace Attorney Investigations Collection) have no Mac build: run one per build with the alignment cuts | checked: the rules resolved on each build's sdk, 2026-10-29 and 2026-10-30 | 12 | [sdk_patches.py](../../dm/tools/sdk_patches.py) | the rules give these builds the same node area cut and the three alignment cuts more; each row keeps the alignment out |
| `build` → `sdk` | rows of builds not on the game drive (56ec2474, 9c73fb73, e01950c5) | address space | blocked: no copy on the drive to compare | judgement | 3 | [sdk_patches.py](../../dm/tools/sdk_patches.py) | likely what the rules give (each names one of their implementations) |
| `build` → `game` | Unity BucketAllocator ALLOC_BUCKET: 255 blocks of 4 MB → 63 | address space | blocked: no extracted main of either Subnautica on the game drive to fingerprint | checked: the bucket allocator of five Unity 2021 and later mains (not Subnautica's), 2026-10-29 | 2 | [Subnautica](../../dm/games/0100429011144000/README.md); [Subnautica: Below Zero](../../dm/games/010014C011146000/README.md) | Unity 2019's constructor call takes the block count as a constant; Unity 2021 and later read the bucket sizes from boot.config with a default of one block (Cult of the Lamb, Monster Train 2, Blasphemous 2, BALL x PIT, Donkey Kong Country Returns HD; checked 2026-10-29) and need no cut, so no Unity rule. A function-matched rule could carry it over the game's updates |
| `build` → `sdk` | VammManager node area and alignment, SDK 4.4.0 (9de92bad) | address space | blocked: one game ships it | judgement | 1 | [sdk_patches.py](../../dm/tools/sdk_patches.py) | an older implementation no rule covers (its large regions aligned to 32 MB, not the rules' 2 MB); a rule once a second game ships it |
| `build` → `engine` | Criterion's 60 fps mode, frame ticks and game step at fixed addresses | frame rate | blocked: one game on that engine here | judgement | 1 | [Need For Speed™ Hot Pursuit Remastered](../../dm/games/010029B0118E8000/README.md) | the studio's engine, which its other games ship |
| `build` → `engine` | Frostbite's frame regulator at a fixed pointer | frame rate | blocked: one Frostbite game here | judgement | 1 | [EA SPORTS FC 27](../../dm/games/0100C49025D3E000/README.md) | engine code other Frostbite games ship (the simulation's own rate is already set by name) |
| `build` → `engine` | Next Level Games' frame limiter target at a fixed address | frame rate | blocked: one game on that engine here | judgement | 1 | [Luigi's Mansion 3](../../dm/games/0100DCA0064A6000/README.md) | the studio's engine, which its other games ship |
| `build` → `engine` | RE Engine's frame limit at a fixed pointer | frame rate | blocked: one RE Engine game here | judgement | 1 | [Monster Hunter Rise](../../dm/games/0100B04011742000/README.md) | engine code other RE Engine games ship |
| `build` → `engine` | ThreadedStreamBuffer load-acquires | race | blocked: no game files of those games on the drive to compare | judgement | 1 | [FINAL FANTASY CRYSTAL CHRONICLES Remastered Edition](../../dm/games/0100CE4010AAC000/README.md) | the race is in Unity 2018.4's ThreadedStreamBuffer, engine code other Unity games of that era ship (Cuphead, AI: THE SOMNIUM FILES, Raging Loop): a function-matched rule per Unity version |
| `build` → `game` | 60 fps frame step (112 sites) | frame rate | blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several | judgement | 1 | [ASTRAL CHAIN](../../dm/games/01007300020FA000/README.md) | the game's own clock and timers (a community 60 fps mod on the host's frame step) |
| `build` → `game` | 60 fps frame step and render scale | frame rate | blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several | judgement | 1 | [The Legend of Zelda: Tears of the Kingdom](../../dm/games/0100F2C0115B6000/README.md) | the game's own timing object |
| `build` → `game` | 60 fps frame step and render scale (ksys::VFR) | frame rate | blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several | judgement | 1 | [The Legend of Zelda: Breath of the Wild](../../dm/games/01007EF00011E000/README.md) | the game's own frame code; the frame-step state page is general |
| `build` → `game` | 60 fps frame step: the KIDS frame task, frame-rate block and event cutscene counters | frame rate | blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several | judgement | 1 | [Hyrule Warriors: Age of Calamity](../../dm/games/01002B00111A2000/README.md) | the game's own frame code; only the host's frame-step state page is shared. Fire Emblem: Three Houses and Taiko Risshiden V DX run on KTGL too, with other frame code |
| `build` → `game` | screen shape: the sizes, the view, the layouts' projection and their edge widgets (DM_SCREEN_ASPECT) | rendering | blocked: the stubs have no function-matched form yet | judgement | 1 | [Animal Crossing: New Horizons](../../dm/games/01006F8002326000/README.md) | the output size is the host's, but where the game takes its sizes, its cameras and its layouts are this build's code |
| `build` → `game` | Hagi coroutine stack region 1 GB → 64 MB | memory | kept: 1.1.4 is the last update; a match over Hagi would serve no other build of this game | checked: the final build 1.1.4 (the only one the profile packs), 2026-11-04 | 1 | [Super Mario 3D All-Stars: Super Mario Sunshine](../../dm/games/010049900F546002/README.md) | a size inside Hagi's own code: nothing the host sees tells a 1 GB reservation it can shrink from one it cannot |

## Summary

| Game | Cuts | Gates | Frame-step sites | Function-matched rules | Host rows | Binding |
|---|---|---|---|---|---|---|
| [Animal Crossing: New Horizons](#animal-crossing-new-horizons) | 0 | 0 | 14 | 0 | 0 | `build` → `game` |
| [ASTRAL CHAIN](#astral-chain) | 0 | 0 | 112 | 0 | 0 | `build` → `game` |
| [Batman: Arkham Knight](#batman-arkham-knight) | 8 | 0 | 0 | 0 | 1 | `build` → `game` ×2 |
| [DARK SOULS: REMASTERED](#dark-souls-remastered) | 2 | 0 | 0 | 0 | 0 | `build` → `game` |
| [EA SPORTS FC 27](#ea-sports-fc-27) | 0 | 0 | 0 | 0 | 1 | `build` → `engine` |
| [FINAL FANTASY CRYSTAL CHRONICLES Remastered Edition](#final-fantasy-crystal-chronicles-remastered-edition) | 8 | 0 | 0 | 0 | 0 | `build` → `engine` |
| [FINAL FANTASY TACTICS - The Ivalice Chronicles](#final-fantasy-tactics---the-ivalice-chronicles) | 2 | 0 | 0 | 0 | 0 | `build` → `game` |
| [Fire Emblem Engage](#fire-emblem-engage) | 1 | 0 | 0 | 0 | 0 | `build` → `engine` |
| [Fire Emblem: Three Houses](#fire-emblem-three-houses) | 12 | 0 | 0 | 0 | 0 | `build` → `game`, `build` → `host` |
| [Hyrule Warriors: Age of Calamity](#hyrule-warriors-age-of-calamity) | 0 | 0 | 5 | 0 | 0 | `build` → `game` |
| [Luigi's Mansion 3](#luigis-mansion-3) | 0 | 0 | 0 | 0 | 1 | `build` → `engine` |
| [Mario + Rabbids® Sparks of Hope](#mario--rabbids-sparks-of-hope) | 1 | 0 | 0 | 0 | 0 | `build` → `game` |
| [Mario Kart World](#mario-kart-world) | 0 | 0 | 1 | 0 | 0 | `game` |
| [Monster Hunter Rise](#monster-hunter-rise) | 0 | 0 | 0 | 0 | 1 | `build` → `engine` |
| [Need For Speed™ Hot Pursuit Remastered](#need-for-speed-hot-pursuit-remastered) | 1 | 0 | 0 | 0 | 5 | `build` → `game`, `build` → `engine` |
| [NieR:Automata The End of YoRHa Edition (010056B015FE8000)](#nierautomata-the-end-of-yorha-edition-010056b015fe8000) | 8 | 0 | 0 | 0 | 1 | `build` → `game` ×2 |
| [NieR:Automata The End of YoRHa Edition (0100B8E016F76000)](#nierautomata-the-end-of-yorha-edition-0100b8e016f76000) | 8 | 0 | 0 | 0 | 1 | `build` → `game` ×2 |
| [Paper Mario: The Thousand-Year Door](#paper-mario-the-thousand-year-door) | 1 | 0 | 1 | 0 | 0 | `build` → `game` |
| [Pokémon Brilliant Diamond](#pokémon-brilliant-diamond) | 0 | 0 | 0 | 0 | 1 | `build` → `engine` |
| [Pokémon Legends: Arceus](#pokémon-legends-arceus) | 0 | 0 | 0 | 1 | 0 | `game` |
| [Subnautica](#subnautica) | 1 | 0 | 0 | 0 | 0 | `build` → `game` |
| [Subnautica: Below Zero](#subnautica-below-zero) | 1 | 0 | 0 | 0 | 0 | `build` → `game` |
| [Super Mario 3D All-Stars: Super Mario Sunshine](#super-mario-3d-all-stars-super-mario-sunshine) | 2 | 0 | 0 | 0 | 0 | `build` → `game` |
| [Super Smash Bros. Ultimate](#super-smash-bros-ultimate) | 11 | 0 | 0 | 1 | 0 | `game` |
| [Taiko Risshiden V DX](#taiko-risshiden-v-dx) | 1 | 0 | 0 | 2 | 0 | `game` |
| [The Legend of Zelda: Breath of the Wild](#the-legend-of-zelda-breath-of-the-wild) | 7 | 0 | 43 | 0 | 0 | `build` → `game` ×2 |
| [The Legend of Zelda: Link's Awakening](#the-legend-of-zelda-links-awakening) | 1 | 0 | 0 | 0 | 0 | `build` → `game` |
| [The Legend of Zelda: Ocarina of Time](#the-legend-of-zelda-ocarina-of-time) | 0 | 0 | 2 | 0 | 0 | `game` ×2 |
| [The Legend of Zelda: Tears of the Kingdom](#the-legend-of-zelda-tears-of-the-kingdom) | 0 | 0 | 9 | 0 | 0 | `build` → `game` |
| [Xenoblade Chronicles 3](#xenoblade-chronicles-3) | 6 | 0 | 0 | 0 | 0 | `build` → `game` |

## Games

### Animal Crossing: New Horizons

[Animal Crossing: New Horizons](../../dm/games/01006F8002326000/README.md), `01006F8002326000`, [patches.py](../../dm/games/01006F8002326000/patches.py).

- **`build` → `game`**, rendering, blocked: the stubs have no function-matched form yet, judgement: screen shape: the sizes, the view, the layouts' projection and their edge widgets (DM_SCREEN_ASPECT). The output size is the host's, but where the game takes its sizes, its cameras and its layouts are this build's code

- **3.0.3 `main`** `ff1d1c05…` ([patches.py:228](../../dm/games/01006F8002326000/patches.py#L228))
  <details><summary>14 frame-step sites</summary>

  - frame step `+0x265140`: nn::ui2d::DrawInfo::SetProjectionMtx: the y row divided by the vertical stretch, layouts in their own shape (bit 6)
  - frame step `+0x27d570`: nn::ui2d::Pane::Calculate after the global matrix: duo_calc (the HUD at the taller screen's edges, full-screen backgrounds stretched)
  - frame step `+0x5c9b80`: graphics create arg +0x60: the display size in the screen's shape (bit 0)
  - frame step `+0x5c9b94`: graphics create arg +0x20: 1280 x the layout height (bit 1)
  - frame step `+0x5cdcc8`: platform config slot 3: the arg's 1920x1080 in the screen's shape (bit 4)
  - frame step `+0x5cdd74`: platform config slot 7: the static display size in the screen's shape (bit 2)
  - frame step `+0x5cddd4`: platform config slot 8: the static layout size 1280.0 x the layout height (bit 3)
  - frame step `+0x7a895c`: field camera: its vertical angle widened so the taller screen keeps 16:9's sides (bit 5)
  - frame step `+0x7a89a8`: field camera: its vertical angle widened so the taller screen keeps 16:9's sides (bit 5)
  - frame step `+0x1527f00`: resolution table entry of the frame (crop, render scale): the height of the screen's shape (bit 7)
  - frame step `+0x1527f2c`: resolution table entry of the frame (crop, render scale): the height of the screen's shape (bit 7)
  - frame step `+0x31cee60`: layouts' DrawInfo: the framebuffer's size in the screen's shape (bit 8)
  - frame step `+0x31cee9c`: layouts' DrawInfo: the framebuffer's size in the screen's shape (bit 8)
  - frame step `+0x386a7a0`: game camera: the vertical angle widened so the taller screen keeps 16:9's sides (bit 5)

  </details>


### ASTRAL CHAIN

[ASTRAL CHAIN](../../dm/games/01007300020FA000/README.md), `01007300020FA000`, [patches.py](../../dm/games/01007300020FA000/patches.py).

- **`build` → `game`**, frame rate, blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several, judgement: 60 fps frame step (112 sites). The game's own clock and timers (a community 60 fps mod on the host's frame step)

- **1.0.1 `main`** `4b159f0f…` ([patches.py:91](../../dm/games/01007300020FA000/patches.py#L91))
  <details><summary>112 frame-step sites</summary>

  - frame step `+0xd5dd4`: frame step (0 = original): [hs] +0x2024 sibling path: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0xd5e28`: frame step (0 = original): S3 +0x2024 exact-zero (D1 handler 0xD3380) +0x2024: b 0xa0e8f0 (was subs w8,w8,#1)
  - frame step `+0xe7f64`: frame step (0 = original): 15-count (v1 site 3) +0x2020: b 0xa0e890 (was subs w8,w8,#1)
  - frame step `+0xf7ce8`: frame step (0 = original): chain bind (v1 site 4) +0x2024: b 0xa0e8c0 (was subs w8,w8,#1)
  - frame step `+0xf8720`: frame step (0 = original): S3 15-count in site-4 routine +0x2020: b 0xa0e860 (was subs w8,w8,#1)
  - frame step `+0x2828ac`: frame step (0 = original): +0xF64 short latch +0xf64: b 0xa0e920 (was subs w8,w8,#1)
  - frame step `+0x283044`: frame step (0 = original): bank +0x1364 buffer +0x1364: b 0xa0eaa0 (was sub w8,w8,#1)
  - frame step `+0x283054`: frame step (0 = original): bank +0x1368 buffer +0x1368: b 0xa0eac0 (was sub w8,w8,#1)
  - frame step `+0x283064`: frame step (0 = original): bank +0x136c buffer +0x136c: b 0xa0eae0 (was sub w8,w8,#1)
  - frame step `+0x283074`: frame step (0 = original): bank +0x138c buffer +0x138c: b 0xa0eb00 (was sub w8,w8,#1)
  - frame step `+0x283084`: frame step (0 = original): bank +0x1378 buffer +0x1378: b 0xa0eb20 (was sub w8,w8,#1)
  - frame step `+0x283094`: frame step (0 = original): bank +0x137c buffer +0x137c: b 0xa0eb40 (was sub w8,w8,#1)
  - frame step `+0x2830a4`: frame step (0 = original): bank +0x1390 buffer +0x1390: b 0xa0eb60 (was sub w8,w8,#1)
  - frame step `+0x2830b4`: frame step (0 = original): bank +0x1370 buffer +0x1370: b 0xa0eb80 (was sub w8,w8,#1)
  - frame step `+0x2830c4`: frame step (0 = original): bank +0x1374 buffer +0x1374: b 0xa0eba0 (was sub w8,w8,#1)
  - frame step `+0x2830d4`: frame step (0 = original): bank +0x13a4 buffer +0x13a4: b 0xa0ebc0 (was sub w8,w8,#1)
  - frame step `+0x2830e4`: frame step (0 = original): bank +0x13a8 buffer +0x13a8: b 0xa0ebe0 (was sub w8,w8,#1)
  - frame step `+0x2830f4`: frame step (0 = original): bank +0x13cc buffer +0x13cc: b 0xa0ec00 (was sub w8,w8,#1)
  - frame step `+0x283100`: frame step (0 = original): +0x14B8 buffer +0x14b8: b 0xa0e950 (was subs w8,w8,#1)
  - frame step `+0x28311c`: frame step (0 = original): +0x46AEF0 tap buffer +0x46aef0: b 0xa0e980 (was subs w8,w8,#1)
  - frame step `+0x283138`: frame step (0 = original): bank +0x1470 buffer +0x1470: b 0xa0ec20 (was sub w8,w8,#1)
  - frame step `+0x283148`: frame step (0 = original): bank +0x1474 buffer +0x1474: b 0xa0ec40 (was sub w8,w8,#1)
  - frame step `+0x283158`: frame step (0 = original): bank +0x1478 buffer +0x1478: b 0xa0ec60 (was sub w8,w8,#1)
  - frame step `+0x283168`: frame step (0 = original): bank +0x147c buffer +0x147c: b 0xa0ec80 (was sub w8,w8,#1)
  - frame step `+0x283178`: frame step (0 = original): bank +0x1480 buffer +0x1480: b 0xa0eca0 (was sub w8,w8,#1)
  - frame step `+0x283188`: frame step (0 = original): bank +0x1484 buffer +0x1484: b 0xa0ecc0 (was sub w8,w8,#1)
  - frame step `+0x283198`: frame step (0 = original): bank +0x1488 buffer +0x1488: b 0xa0ece0 (was sub w8,w8,#1)
  - frame step `+0x2831a8`: frame step (0 = original): bank +0x148c buffer +0x148c: b 0xa0ed00 (was sub w8,w8,#1)
  - frame step `+0x2831b8`: frame step (0 = original): bank +0x1490 buffer +0x1490: b 0xa0ed20 (was sub w8,w8,#1)
  - frame step `+0x2831c8`: frame step (0 = original): bank +0x1450 buffer +0x1450: b 0xa0ed40 (was sub w8,w8,#1)
  - frame step `+0x2831dc`: frame step (0 = original): bank +0x1454 buffer +0x1454: b 0xa0ed60 (was sub w8,w8,#1)
  - frame step `+0x283294`: frame step (0 = original): [hs] +0x46AE28 window: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x283360`: frame step (0 = original): [hs] +0x46ADAC exact-zero: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x283a94`: frame step (0 = original): [isubs] +0x46B4C4 lockout: b cave 0xa0eea0 (was subs w10, w10, #1)
  - frame step `+0x2846f0`: frame step (0 = original): [up] +0x46B62C up-counter: b cave 0xa0eed0 (was add w10, w9, #1)
  - frame step `+0x284ad4`: frame step (0 = original): [hs] +0x14E0 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x284af0`: frame step (0 = original): [hs] +0x46AEF8 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x284b00`: frame step (0 = original): [hs] +0xDA4 window (set 15 at 0x325300; next to r3 0x284AD4/0x284AF0): bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x284bb8`: frame step (0 = original): [hs] +0x46AF00 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x284bf4`: frame step (0 = original): [hs] +0x46AF04 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x285464`: frame step (0 = original): [hs] +0x46AE10 queue window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x2856f8`: frame step (0 = original): [hs] +0x46AE14 re-injected press window: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x286c2c`: frame step (0 = original): [upmin1] +0xC50 tap/hold count-up: b cave 0xa0eee4 (was add w9, w9, #1)
  - frame step `+0x286e38`: frame step (0 = original): [hs] +0x14E0 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x286f98`: frame step (0 = original): [hs] +0x14E0 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x287044`: frame step (0 = original): [hs] +0x14E0 window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x28759c`: frame step (0 = original): +0x14D4 buffer +0x14d4: b 0xa0e9b0 (was subs w8,w8,#1)
  - frame step `+0x2875ac`: frame step (0 = original): +0x14D8 buffer +0x14d8: b 0xa0e9e0 (was subs w8,w8,#1)
  - frame step `+0x2875bc`: frame step (0 = original): +0x1414 buffer +0x1414: b 0xa0ea10 (was subs w8,w8,#1)
  - frame step `+0x2875cc`: frame step (0 = original): +0x149C buffer +0x149c: b 0xa0ea40 (was subs w8,w8,#1)
  - frame step `+0x2875dc`: frame step (0 = original): +0x14DC buffer +0x14dc: b 0xa0ea70 (was subs w8,w8,#1)
  - frame step `+0x287694`: frame step (0 = original): [hs] +0x13A0 second-tap window, path A (b.ge -> 0x28772C mov w10,w9; str): bl stub_w10w9 0xa0efcc (was subs w9, w10, #1)
  - frame step `+0x2876d4`: frame step (0 = original): [hs] +0x14D4 r2-sibling path (shares store 0x2875A4 with r2 0x28759C): bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x287724`: frame step (0 = original): [hs] +0x13A0 second-tap window, path B (b.lt -> 0x287734): bl stub_w10w9 0xa0efcc (was subs w9, w10, #1)
  - frame step `+0x287738`: frame step (0 = original): [hs] +0x139C window (set 15 with bank +0x137C at 0x287764/0x287790): bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x28783c`: frame step (0 = original): [hs] +0x13B0 window (set 15 at 0x287830 next to bank +0x13A8 = 15): bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288f40`: frame step (0 = original): [hs] lockout bank +0x46a8b0: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288f5c`: frame step (0 = original): [hs] lockout bank +0x46a8c4: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288f78`: frame step (0 = original): [hs] lockout bank +0x46b3a8: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288f94`: frame step (0 = original): [hs] lockout bank +0x46b3ac: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288fb0`: frame step (0 = original): [hs] lockout bank +0x46b460: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288fcc`: frame step (0 = original): [hs] lockout bank +0x46b464: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x288fe8`: frame step (0 = original): [hs] lockout bank +0x46b490: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x289004`: frame step (0 = original): [hs] lockout bank +0x46b49c: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x289020`: frame step (0 = original): [hs] lockout bank +0x46b638: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x28903c`: frame step (0 = original): [hs] lockout bank +0x46b640: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x289244`: frame step (0 = original): [hs] lockout bank +0x46b658: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x289260`: frame step (0 = original): [hs] lockout bank +0x46b664: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x28927c`: frame step (0 = original): [hs] lockout bank +0x46b66c: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x289298`: frame step (0 = original): [hs] lockout bank +0x46b39c: bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x308a9c`: frame step (0 = original): combo cue (v1 site 1) +0x1290: b 0xa0e830 (was subs w8,w8,#1)
  - frame step `+0x32cac8`: frame step (0 = original): [hs] player deferred hitstop delay +0x7e88; exact-zero -> 0x91D6A0(w2=0): bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x32cdc0`: frame step (0 = original): [hs] player deferred hitstop delay +0x7e94; exact-zero -> 0x91D6A0(w2=0): bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x32d0b8`: frame step (0 = original): [hs] player deferred hitstop delay +0x7e80; exact-zero -> 0x91D6A0(w2=0): bl hs_w9 0xa0edbc (was subs w9, w9, #1)
  - frame step `+0x3a2d40`: frame step (0 = original): was fmin s8,s0,s10 -> bl 0x5763E4
  - frame step `+0x3a2d80`: frame step (0 = original): was fmin s8,s1,s10 -> bl 0x5763EC
  - frame step `+0x3a2dc0`: frame step (0 = original): was fcsel s8,s10,s9,gt -> bl 0x5763F4
  - frame step `+0x48be14`: frame step (0 = original): Replace FCVTZS: ldr w8,[x8,#0xD8]
  - frame step `+0x4f3d30`: frame step (0 = original): [hs] +0x38 delay set by 0x4F27A0(w3); exact-zero -> 0x4F27A0(+0x3C,+0x40) issues the scale: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3d5c`: frame step (0 = original): [hs] +0x34 duration of scale +0x30; exact-zero -> sound 0x8DD890 + 0x923B90(+0xE8); expiry -> +0x30=1.0: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3d98`: frame step (0 = original): [hs] +0x48 duration of scale +0x44; exact-zero -> +0x14=0; expiry -> +0x44=1.0: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3db0`: frame step (0 = original): [hs] +0x74 duration of scale +0x70; exact-zero -> +0x10=0, 0x923B90(+0x100); expiry -> +0x70=1.0: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3e4c`: frame step (0 = original): [hs] +0xA8 request suppression window: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3e64`: frame step (0 = original): [hs] +0x48 sibling path after +0x34 expiry: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3e78`: frame step (0 = original): [hs] +0x74 sibling path after +0x48 expiry: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3f04`: frame step (0 = original): [hs] +0xA8 request suppression window, b.lt path: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3f14`: frame step (0 = original): [hs] +0xA4 duration of scale +0xA0: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3f3c`: frame step (0 = original): [hs] +0x54 duration of scale +0x50: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3f54`: frame step (0 = original): [hs] +0x80 hold-request delay: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3f88`: frame step (0 = original): [hs] +0x54 sibling path after +0xA4 expiry: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f3fb0`: frame step (0 = original): [hs] +0x8C cue delay after request release; exact-zero -> sound 0x8DD890: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x4f4010`: frame step (0 = original): [clamp1] +0x8C clamped decrement: b cave 0xa0ee70 (was sub w9, w9, #1)
  - frame step `+0x4f4018`: frame step (0 = original): [up] +0x84 freeze-phase count-up: b cave 0xa0ee8c (was add w8, w8, #1)
  - frame step `+0x4f406c`: frame step (0 = original): [ramp] manager +0x7C ramp step c*T: b cave 0xa0efac (was ldr s0, [x19, #0x7c]; 0x4F4070 now skipped)
  - frame step `+0x4f41b0`: frame step (0 = original): [hs] +0xB4 window; expiry -> +0xAC=0: bl hs_w8 0xa0ed80 (was subs w8, w8, #1)
  - frame step `+0x57e7dc`: frame step (0 = original): Load whole ticks: ldr w8,[x24,#0xD8]
  - frame step `+0x57e7e0`: frame step (0 = original): Zero ticks: cbz w8,0x57E810
  - frame step `+0x91dbdc`: frame step (0 = original): First sample: cbz x8,0xA0E828
  - frame step `+0x91dc10`: frame step (0 = original): Measured sample: b 0xA0E7D0
  - frame step `+0x91de50`: frame step (0 = original): [isubs] clock +0x34 delay: b cave 0xa0ef04 (was subs w16, w16, #1)
  - frame step `+0x91dee8`: frame step (0 = original): [naive] clock +0x30 duration: b cave 0xa0ef34 (was subs w16, w16, #1)
  - frame step `+0x9abc68`: frame step (0 = original): [rumble] rumble channel 0 count +0x48: b stub 0xa0ef5c -> rh_w8 (was subs w9, w8, #1)
  - frame step `+0x9abc7c`: frame step (0 = original): [rumble] rumble channel count +0x60: b stub 0xa0ef64 -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abcc0`: frame step (0 = original): [rumble] rumble channel count +0x60: b stub 0xa0ef6c -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abcdc`: frame step (0 = original): [rumble] rumble channel count +0x78: b stub 0xa0ef7c -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abd34`: frame step (0 = original): [rumble] rumble channel count +0x60: b stub 0xa0ef74 -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abd50`: frame step (0 = original): [rumble] rumble channel count +0x78: b stub 0xa0ef84 -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abd6c`: frame step (0 = original): [rumble] rumble channel count +0x90: b stub 0xa0ef94 -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abdd0`: frame step (0 = original): [rumble] rumble channel count +0x78: b stub 0xa0ef8c -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abdec`: frame step (0 = original): [rumble] rumble channel count +0x90: b stub 0xa0ef9c -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abe8c`: frame step (0 = original): [rumble] rumble channel count +0x90: b stub 0xa0efa4 -> rh_w9 (was subs w10, w9, #1)
  - frame step `+0x9abf40`: frame step (0 = original): [up] pad auto-repeat count +0x30: b cave 0xa0ef48 (was add w9, w9, #1)

  </details>


### Batman: Arkham Knight

[Batman: Arkham Knight](../../dm/games/0100ACD0163D0000/README.md), `0100ACD0163D0000`, [patches.py](../../dm/games/0100ACD0163D0000/patches.py).

- **`build` → `game`**, race, gap, judgement: task ring push and pop barriers. A data race in the game's own task ring
- **`build` → `game`**, address space, gap, judgement: UE3's GMalloc setup skipped, the host allocator in (hle_uemalloc.c). UE3 inlines the allocator's constructor into the GMalloc setup and has its own vtable layout (25 slots, 32-bit sizes), so the Unreal 4/5 discovery does not apply

- **1.0.5 `main`** `feae83dc…` ([patches.py:11](../../dm/games/0100ACD0163D0000/patches.py#L11))
  - cut `+0x192ec14`: GMalloc setup: adrp x8 (first instruction of the inlined allocator constructor, 1 GB + 37 GB of address space) → b 0x192fea4 (__cxa_guard_release); the host allocator is in the object already (hle_uemalloc.c)
  - cut `+0xc5ae24`: queue push: and x10, x10, #0xffff → and x11, x10, #0xffff (w10 keeps the tail)
  - cut `+0xc5ae28`: queue push: str x8, [x9, x10, lsl #3] → str x8, [x9, x11, lsl #3] (the item)
  - cut `+0xc5ae2c`: queue push: ldr w8, [x19, #0x18] (the tail again) → dmb ishst
  - cut `+0xc5ae30`: queue push: add w8, w8, #1 → add w8, w10, #1 (then str w8, [x19, #0x18]: the new tail)
  - cut `+0xc5ab8c`: queue pop: ldr x8, [x19] → dmb ishld (after the tail load; w8 = head)
  - cut `+0xc5ab94`: queue pop: ldr w9, [x19, #0x1c] (the head again) → and x9, x8, #0xffff
  - cut `+0xc5ab98`: queue pop: and x9, x9, #0xffff → ldr x8, [x19] (the ring; then ldr x8, [x8, x9, lsl #3]: the item)
  - host [hle_uemalloc.c:41](../../dm/host/hle_uemalloc.c#L41): Unreal's allocator on a host malloc zone

### DARK SOULS: REMASTERED

[DARK SOULS: REMASTERED](../../dm/games/01004AB00A260000/README.md), `01004AB00A260000`, [patches.py](../../dm/games/01004AB00A260000/patches.py).

- **`build` → `game`**, frame rate, gap, judgement: frame limiter 30 → 60 fps and the 1/60 update step. The game's own limiter constant and fixed step

- **1.0.3 `main`** `df3766a2…` ([patches.py:10](../../dm/games/01004AB00A260000/patches.py#L10))
  - cut `+0x706fa4`: frame limiter target: mov w1,#30 → mov w1,#60 (main+0x707090 sleeps out 1000 / fps ms since the last frame)
  - cut `+0x667904`: frame update step: ldr s8,[x8,#0x6ec] (1/30) → ldr s8,[x8,#0x834] (1/60), passed to main+0x6a337c

### EA SPORTS FC 27

[EA SPORTS FC 27](../../dm/games/0100C49025D3E000/README.md), `0100C49025D3E000`.

- **`build` → `engine`**, frame rate, blocked: one Frostbite game here, judgement: Frostbite's frame regulator at a fixed pointer. Engine code other Frostbite games ship (the simulation's own rate is already set by name)

- **1.8d.310c `main`** `a48c0de3…`
  - host [hle_fpslock.c:56](../../dm/host/hle_fpslock.c#L56): engine frame limit set to fps_target: FIFA frame regulator

### FINAL FANTASY CRYSTAL CHRONICLES Remastered Edition

[FINAL FANTASY CRYSTAL CHRONICLES Remastered Edition](../../dm/games/0100CE4010AAC000/README.md), `0100CE4010AAC000`, [patches.py](../../dm/games/0100CE4010AAC000/patches.py).

- **`build` → `engine`**, race, blocked: no game files of those games on the drive to compare, judgement: ThreadedStreamBuffer load-acquires. The race is in Unity 2018.4's ThreadedStreamBuffer, engine code other Unity games of that era ship (Cuphead, AI: THE SOMNIUM FILES, Raging Loop): a function-matched rule per Unity version

- **1.0.3 `main`** `e1d8b399…` ([patches.py:14](../../dm/games/0100CE4010AAC000/patches.py#L14))
  - cut `+0x1e67a50`: stream reader going to sleep: ldr w8,[x8] → ldar (write position after the store-release of "reader sleeping")
  - cut `+0x1e683a8`: stream writer: ldr w8,[x8] → ldar ("reader sleeping" after the store-release of the write position)
  - cut `+0x1e68498`: stream writer: ldr w8,[x8] → ldar ("reader sleeping" after the store-release of the write position)
  - cut `+0x1e6851c`: stream writer: ldr w8,[x8] → ldar ("reader sleeping" after the store-release of the write position)
  - cut `+0x1e687c8`: stream writer going to sleep: ldr w9,[x9] → ldar (read position after the store-release of "writer sleeping")
  - cut `+0x1e6805c`: stream reader: ldr w8,[x8] → ldar ("writer sleeping" after the store-release of the read position)
  - cut `+0x1e68154`: stream reader: ldr w8,[x8] → ldar ("writer sleeping" after the store-release of the read position)
  - cut `+0x1e681d8`: stream reader: ldr w8,[x8] → ldar ("writer sleeping" after the store-release of the read position)

### FINAL FANTASY TACTICS - The Ivalice Chronicles

[FINAL FANTASY TACTICS - The Ivalice Chronicles](../../dm/games/010038B015560000/README.md), `010038B015560000`, [patches.py](../../dm/games/010038B015560000/patches.py).

- **`build` → `game`**, race, gap, judgement: job pool wake-up. A lost wake-up in the game's own job pool, not a host or SDK difference

- **1.4.0 `main`** `3cfd4578…` ([patches.py:11](../../dm/games/010038B015560000/patches.py#L11))
  - cut `+0x12554`: job pool wake: ldr x0,[x0] → str x0,[x0,#8] (pending = nonzero: the woken worker signals once more)
  - cut `+0x12558`: job pool wake: b SignalEvent → b 0x1254c (ldr x0,[x0]; b SignalEvent)

### Fire Emblem Engage

[Fire Emblem Engage](../../dm/games/0100A6301214E000/README.md), `0100A6301214E000`, [patches.py](../../dm/games/0100A6301214E000/patches.py).

- **`build` → `engine`**, frame rate, gap, judgement: Unity QualitySettings.vSyncCount held at 1. An IL2CPP player registers the setter by its icall name, so the place can be found in any Unity game; holding it at 1 stays this profile's choice (its logic steps by the count)

- **2.0.0 `main`** `8c08b971…` ([patches.py:11](../../dm/games/0100A6301214E000/patches.py#L11))
  - cut `+0x32f92d4`: QualitySettings.set_vSyncCount wrapper: argument mov w19,w0 → mov w19,#1 (the 60 fps path of the game itself)

### Fire Emblem: Three Houses

[Fire Emblem: Three Houses](../../dm/games/010055D009F78000/README.md), `010055D009F78000`, [patches.py](../../dm/games/010055D009F78000/patches.py).

- **`build` → `game`**, frame rate, gap, judgement: render intervals, the forced-interval flag and the render-wait timeout. The game's own tables, flag and timeout
- **`build` → `host`**, power, gap, checked: Mac runs with the cut undone, 2026-10-26 (the game note): frame limiter wait: yield → sleep. Without it the host's yield back-off (thr_yield) holds 59.7 to 59.8 fps, at 0.9 to 1.2 W of CPU against 0.14 to 0.42 W (2026-10-26): a back-off that reaches a yield-and-tick loop's deadline sooner would make the cut unnecessary for every game

- **1.2.0 `main`** `89048449…` ([patches.py:11](../../dm/games/010055D009F78000/patches.py#L11))
  - cut `+0xd13de0`: per-render-mode present interval table {2,1,2,2,1,2} → all 1 (60 fps; the game logic already runs at 60 updates a second)
  - cut `+0xd13e40`: per-render-mode interval as float {2.0,1.0,2.0,2.0,1.0,2.0} → all 1.0 (render-thread per-frame steps)
  - cut `+0x50fb7c`: render thread forced interval 2: orr w8,w9,w8 (either flag) → mov w8,wzr (the mode's interval, 1)
  - cut `+0x5be4c0`: frame limiter wait: bl YieldThread → sub x0,x23,x8 (time left, 100 ns units)
  - cut `+0x5be4c4`: frame limiter wait: bl GetSystemTick → lsl x1,x0,#5
  - cut `+0x5be4c8`: frame limiter wait: ldr x8,[x19] → add x0,x1,x0,lsl #6 (96 ns per 100 ns left)
  - cut `+0x5be4cc`: frame limiter wait: sub x8,x0,x8 → bl nn::os::SleepThread (PLT main+0xafc300)
  - cut `+0x5be4d0`: frame limiter wait: mul x8,x8,x20 → b main+0x5be44c (read the tick and compare again)
  - cut `+0x50f8e8`: render thread wait timeout: fmov s1,#1.0 → adrp x8,#0xcb7000
  - cut `+0x50f8ec`: render thread wait timeout: fdiv s0,s1,s0 → ldr s8,[x8,#0xb50] (1000.0)
  - cut `+0x50f8f0`: render thread wait timeout: adrp x8,#0xcb7000 → fdiv s0,s8,s0 (1000/fps; the fmul by s8 that follows makes it µs)
  - cut `+0x50f8f4`: render thread wait timeout: ldr s8,[x8,#0xb50] → nop (moved up)

### Hyrule Warriors: Age of Calamity

[Hyrule Warriors: Age of Calamity](../../dm/games/01002B00111A2000/README.md), `01002B00111A2000`, [patches.py](../../dm/games/01002B00111A2000/patches.py).

- **`build` → `game`**, frame rate, blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several, judgement: 60 fps frame step: the KIDS frame task, frame-rate block and event cutscene counters. The game's own frame code; only the host's frame-step state page is shared. Fire Emblem: Three Houses and Taiko Risshiden V DX run on KTGL too, with other frame code

- **1.3.0 `main`** `c3cf52bf…` ([patches.py:113](../../dm/games/01002B00111A2000/patches.py#L113))
  - frame step `+0x857d7c`: event cutscene's frame: stepped on every other update at a 60 fps cap (state page vsyncs per update; 30 fps frames, as on the Switch)
  - frame step `+0x857da0`: event cutscene's frames left: stepped on every other update at a 60 fps cap (state page vsyncs per update; 30 fps frames, as on the Switch)
  - frame step `+0x8d94b0`: KTGL device config present interval: 1 above a 30 fps cap, else the game's 2 (state page target fps)
  - frame step `+0x166dab4`: KIDS frame task: fps and the frame-rate block = the cap, vsyncs per update marked; device frame rate 59.94 / vsyncs (state page target fps; 0 = the game's 30)
  - frame step `+0x166dc60`: KIDS frame task: the frame-rate object's steps × its fps × vsyncs per update / 60 (state page target fps; 0 = as the game sets them)

### Luigi's Mansion 3

[Luigi's Mansion 3](../../dm/games/0100DCA0064A6000/README.md), `0100DCA0064A6000`.

- **`build` → `engine`**, frame rate, blocked: one game on that engine here, judgement: Next Level Games' frame limiter target at a fixed address. The studio's engine, which its other games ship

- **1.4.0 `main`** `79e5950f…`
  - host [hle_fpslock.c:41](../../dm/host/hle_fpslock.c#L41): engine frame limit set to fps_target: NLG frame limiter target

### Mario + Rabbids® Sparks of Hope

[Mario + Rabbids® Sparks of Hope](../../dm/games/0100317013770000/README.md), `0100317013770000`, [patches.py](../../dm/games/0100317013770000/patches.py).

- **`build` → `game`**, address space, gap, judgement: unused 272-byte slot pool: 4,194,304 → 65,536 slots. Sparks of Hope's own init (Kingdom Battle has none)

- **1.6.2225577 `main`** `5b76a43b…` ([patches.py:13](../../dm/games/0100317013770000/patches.py#L13))
  - cut `+0x94354`: Unused 272-byte slot pool: 4,194,304 -> 65,536 slots, 1.06 GB -> 17 MB of address space (mov w1,#0x10000)

### Mario Kart World

[Mario Kart World](../../dm/games/0400C3F00006E000/README.md), `0400C3F00006E000`, [patches.py](../../dm/games/0400C3F00006E000/patches.py).

- **`game`**, frame rate, at goal, checked: v0 main: one function with this fingerprint, the site and its free registers read by disassembly (2026-11-08): frame interval from the host's step. The game's own interval choice, found by its function's fingerprint on any build that keeps the function

- **function-matched frame step** (`main` of builds without FRAME_STEP): frame interval from the host's step: a function of 0x290 bytes, `+0xa0` in it

### Monster Hunter Rise

[Monster Hunter Rise](../../dm/games/0100B04011742000/README.md), `0100B04011742000`.

- **`build` → `engine`**, frame rate, blocked: one RE Engine game here, judgement: RE Engine's frame limit at a fixed pointer. Engine code other RE Engine games ship

- **16.0.2 `main`** `c9a3dd77…`
  - host [hle_fpslock.c:37](../../dm/host/hle_fpslock.c#L37): engine frame limit set to fps_target: RE Engine frame limit

### Need For Speed™ Hot Pursuit Remastered

[Need For Speed™ Hot Pursuit Remastered](../../dm/games/010029B0118E8000/README.md), `010029B0118E8000`, [patches.py](../../dm/games/010029B0118E8000/patches.py).

- **`build` → `game`**, frame rate, gap, judgement: frame limiter spin: its branch back cut. The engine's own spin limiter; a function-matched rule could carry it over the game's updates
- **`build` → `engine`**, frame rate, blocked: one game on that engine here, judgement: Criterion's 60 fps mode, frame ticks and game step at fixed addresses. The studio's engine, which its other games ship

- **1.0.3 `main`** `799d1061…` ([patches.py:7](../../dm/games/010029B0118E8000/patches.py#L7))
  - cut `+0x4835a4`: frame limiter spin: b.gt main+0x483588 → nop (the host paces the frames)
  - host [hle_fpslock.c:46](../../dm/host/hle_fpslock.c#L46): engine frame limit set to fps_target: Criterion 60 fps mode
  - host [hle_fpslock.c:47](../../dm/host/hle_fpslock.c#L47): engine frame limit set to fps_target: Criterion frame ticks
  - host [hle_fpslock.c:48](../../dm/host/hle_fpslock.c#L48): engine frame limit set to fps_target: Criterion frame ticks / 10
  - host [hle_fpslock.c:49](../../dm/host/hle_fpslock.c#L49): engine frame limit set to fps_target: Criterion 2D game step
  - host [hle_fpslock.c:50](../../dm/host/hle_fpslock.c#L50): engine frame limit set to fps_target: Criterion 3D game step

### NieR:Automata The End of YoRHa Edition (010056B015FE8000)

[NieR:Automata The End of YoRHa Edition (010056B015FE8000)](../../dm/games/010056B015FE8000/README.md), `010056B015FE8000`, [patches.py](../../dm/games/010056B015FE8000/patches.py).

- **`build` → `game`**, frame rate, gap, checked: both releases' mains, where the host's rows for them were found: 60 fps intervals and dynamic-resolution constants. The game's own constants; the Asian release's function is the global one's 0x13c0 further on, so one function-matched rule could serve both releases
- **`build` → `game`**, frame rate, gap, checked: both releases' mains, where these rows were found: NieR's frame interval and dynamic-resolution floor at fixed addresses. The game's own display object; the Asian release's function is the global one's 0x13c0 further on, so the rewriter's function match could give the host both releases' addresses

- **1.0.3 `main`** `3c10ec35…` ([patches.py:9](../../dm/games/010056B015FE8000/patches.py#L9))
  - cut `+0x591198`: 60 FPS present interval mode: 1 -> 0
  - cut `+0x9bad68`: 60 FPS NVN present interval: 2 -> 1
  - cut `+0x9bf528`: handheld lower bound follows preset minimum
  - cut `+0x9bf534`: docked lower bound follows preset minimum
  - cut `+0x9bf434`: dynamic resolution: bad frame cost 45 -> 22.5 ms at 60 fps
  - cut `+0x9bf484`: dynamic resolution: optimal frame cost 32.01 -> 16.005 ms at 60 fps (first load)
  - cut `+0x9bf4d4`: dynamic resolution: optimal frame cost 32.01 -> 16.005 ms at 60 fps (second load)
  - cut `+0x9bf4f8`: dynamic resolution: good frame cost 30 -> 15 ms at 60 fps
  - launcher capabilities: DYNAMIC_RESOLUTION
  - host [hle_fpslock.c:72](../../dm/host/hle_fpslock.c#L72): frame interval and dynamic-resolution floor

### NieR:Automata The End of YoRHa Edition (0100B8E016F76000)

[NieR:Automata The End of YoRHa Edition (0100B8E016F76000)](../../dm/games/0100B8E016F76000/README.md), `0100B8E016F76000`, [patches.py](../../dm/games/0100B8E016F76000/patches.py).

- **`build` → `game`**, frame rate, gap, checked: both releases' mains, where the host's rows for them were found: 60 fps intervals and dynamic-resolution constants. The game's own constants; the Asian release's function is the global one's 0x13c0 further on, so one function-matched rule could serve both releases
- **`build` → `game`**, frame rate, gap, checked: both releases' mains, where these rows were found: NieR's frame interval and dynamic-resolution floor at fixed addresses. The game's own display object; the Asian release's function is the global one's 0x13c0 further on, so the rewriter's function match could give the host both releases' addresses

- **1.0.3 `main`** `98397a10…` ([patches.py:9](../../dm/games/0100B8E016F76000/patches.py#L9))
  - cut `+0x9c07f4`: dynamic resolution: bad frame cost 45 -> 22.5 ms at 60 fps
  - cut `+0x9c0844`: dynamic resolution: optimal frame cost 32.01 -> 16.005 ms at 60 fps (first load)
  - cut `+0x9c0894`: dynamic resolution: optimal frame cost 32.01 -> 16.005 ms at 60 fps (second load)
  - cut `+0x9c08b8`: dynamic resolution: good frame cost 30 -> 15 ms at 60 fps
  - cut `+0x591198`: NieR 1.0.3 frame interval default: 30 -> 60 fps (the mode the setter main+0x9c0590 stores at display +0x504)
  - cut `+0x9bc128`: NieR 1.0.3 NVN present interval default: 30 -> 60 fps (stored at the device's +0x9c160)
  - cut `+0x9c08e8`: dynamic resolution lower bound follows the selected preset
  - cut `+0x9c08f4`: dynamic resolution lower bound follows the selected preset
  - launcher capabilities: DYNAMIC_RESOLUTION
  - host [hle_fpslock.c:73](../../dm/host/hle_fpslock.c#L73): frame interval and dynamic-resolution floor

### Paper Mario: The Thousand-Year Door

[Paper Mario: The Thousand-Year Door](../../dm/games/0100ECD018EBE000/README.md), `0100ECD018EBE000`, [patches.py](../../dm/games/0100ECD018EBE000/patches.py).

- **`build` → `game`**, frame rate, gap, judgement: frame step floor 2 → 1 vsync, and its frame step. The game's own clock floor and step; MATCH_CUTS and MATCH_FRAME_STEP could carry the cut and the stub, both near the step's function (main+0x2e7750; one function not checked yet)

- **1.0.1 `main`** `0effe4af…` ([patches.py:5](../../dm/games/0100ECD018EBE000/patches.py#L5))
  - cut `+0x2e77a4`: frame step floor in 60 Hz vsyncs: mov w9,#2 → mov w9,#1 (the game steps by the vsyncs that passed, down to one)
  - frame step `+0x2e77f8`: frame step: the base clock steps by the host's vsyncs (state page target fps; 0 = the game's measured step)

### Pokémon Brilliant Diamond

[Pokémon Brilliant Diamond](../../dm/games/0100000011D90000/README.md), `0100000011D90000`.

- **`build` → `engine`**, frame rate, gap, judgement: Unity's Application.targetFrameRate at a fixed address. An IL2CPP player registers the setter by its icall name, so the field can be found in any Unity game; whether to raise it stays the profile's

- **1.3.0 `main`** `94ceae32…`
  - host [hle_fpslock.c:32](../../dm/host/hle_fpslock.c#L32): engine frame limit set to fps_target: Unity targetFrameRate

### Pokémon Legends: Arceus

[Pokémon Legends: Arceus](../../dm/games/01001F5010DFA000/README.md), `01001F5010DFA000`, [patches.py](../../dm/games/01001F5010DFA000/patches.py).

- **`game`**, runtime, at goal, checked: function-matched on 1.1.1, the only build on hand: exactly one match, a boot to the field setup, and the patched function run on the module's own bytes in a small interpreter for both null paths. Issue #712's reporters ran the earlier cuts for about 7 hours with no crash; the path itself has not been reached with these cuts: capture demo: the empty result when the weak reference at +0x88 is unset or dead. The game's own function dereferences its own weak reference; no host service is on the path, so no host or engine rule can hold it. Whether another Game Freak game shares the function is unchecked

- **function-matched** (`main` of builds without CUTS): capture demo: the empty result when the weak reference at +0x88 is unset or dead: 1 function, 5 cuts

### Subnautica

[Subnautica](../../dm/games/0100429011144000/README.md), `0100429011144000`, [patches.py](../../dm/games/0100429011144000/patches.py).

- **`build` → `game`**, address space, blocked: no extracted main of either Subnautica on the game drive to fingerprint, checked: the bucket allocator of five Unity 2021 and later mains (not Subnautica's), 2026-10-29: Unity BucketAllocator ALLOC_BUCKET: 255 blocks of 4 MB → 63. Unity 2019's constructor call takes the block count as a constant; Unity 2021 and later read the bucket sizes from boot.config with a default of one block (Cult of the Lamb, Monster Train 2, Blasphemous 2, BALL x PIT, Donkey Kong Country Returns HD; checked 2026-10-29) and need no cut, so no Unity rule. A function-matched rule could carry it over the game's updates

- **1.23.83358 `main`** `b3db5a1e…` ([patches.py:13](../../dm/games/0100429011144000/patches.py#L13))
  - cut `+0x60ea64`: BucketAllocator ALLOC_BUCKET: at most 255 blocks of 4 MB (a 1 GB address region) → 63 (256 MB)

### Subnautica: Below Zero

[Subnautica: Below Zero](../../dm/games/010014C011146000/README.md), `010014C011146000`, [patches.py](../../dm/games/010014C011146000/patches.py).

- **`build` → `game`**, address space, blocked: no extracted main of either Subnautica on the game drive to fingerprint, checked: the bucket allocator of five Unity 2021 and later mains (not Subnautica's), 2026-10-29: Unity BucketAllocator ALLOC_BUCKET: 255 blocks of 4 MB → 63. Unity 2019's constructor call takes the block count as a constant; Unity 2021 and later read the bucket sizes from boot.config with a default of one block (Cult of the Lamb, Monster Train 2, Blasphemous 2, BALL x PIT, Donkey Kong Country Returns HD; checked 2026-10-29) and need no cut, so no Unity rule. A function-matched rule could carry it over the game's updates

- **1.23.55063 `main`** `5b050c55…` ([patches.py:14](../../dm/games/010014C011146000/patches.py#L14))
  - cut `+0x6517f4`: BucketAllocator ALLOC_BUCKET: at most 255 blocks of 4 MB (a 1 GB address region) → 63 (256 MB)

### Super Mario 3D All-Stars: Super Mario Sunshine

[Super Mario 3D All-Stars: Super Mario Sunshine](../../dm/games/010049900F546002/README.md), `010049900F546002`, [patches.py](../../dm/games/010049900F546002/patches.py).

- **`build` → `game`**, memory, kept: 1.1.4 is the last update; a match over Hagi would serve no other build of this game, checked: the final build 1.1.4 (the only one the profile packs), 2026-11-04: Hagi coroutine stack region 1 GB → 64 MB. A size inside Hagi's own code: nothing the host sees tells a 1 GB reservation it can shrink from one it cannot

- **1.1.4 `main`** `b21e3733…` ([patches.py:7](../../dm/games/010049900F546002/patches.py#L7))
  - cut `+0x151214`: coroutine stack region size: orr w2,wzr,#0x40000000 → mov w2,#0x4000000 (1 GB → 64 MB)
  - cut `+0x151398`: coroutine stack region size, the other start path: 1 GB → 64 MB

### Super Smash Bros. Ultimate

[Super Smash Bros. Ultimate](../../dm/games/01006A800016E000/README.md), `01006A800016E000`, [patches.py](../../dm/games/01006A800016E000/patches.py).

- **`game`**, address space, at goal, checked: MATCH_CUTS enrolled on its builds: engine region 62 GB → 4 GB (11 cuts in four functions). Function-matched for builds of the same code (MATCH_CUTS); the region and its node pool are the nu:: engine's own

- **13.0.5 `main`** `21450c64…` ([patches.py:10](../../dm/games/01006A800016E000/patches.py#L10))
  - cut `+0x37c9a5c`: AllocateAddressRegion size mov x1,#0xf80000000 → mov x1,#0x100000000 (62 GB → 4 GB)
  - cut `+0x37c9a6c`: node pool top check, low part mov x9,#0xffffffff0 → mov x9,#0xfff0
  - cut `+0x37c9a70`: node pool start mov x11,#0x7f200000 → mov x11,#0xff200000
  - cut `+0x37c9a74`: node pool top check movk x9,#0x7f20,lsl #16 → movk x9,#0xff20,lsl #16 (0xff20fff0)
  - cut `+0x37c9a78`: node pool start movk x11,#0xf,lsl #32 → movk x11,#0,lsl #32 (0xff200000 = 4 GB − 14 MB)
  - cut `+0x37c9a9c`: node pool bound: region end mov x9,#0xf80000000 → mov x9,#0x100000000
  - cut `+0x37c9b98`: first free range in 64 KB units mov w1,#0x7f20 → mov w1,#0xff20
  - cut `+0x37c9b9c`: first free range movk w1,#0xf,lsl #16 → movk w1,#0,lsl #16 (0xff20 units = 4 GB − 14 MB)
  - cut `+0x37c9c50`: node pool bound: region end mov x9,#0xf80000000 → mov x9,#0x100000000
  - cut `+0x37ca3cc`: node pool bound: region end mov x8,#0xf80000000 → mov x8,#0x100000000
  - cut `+0x37caf68`: node pool bound: region end mov x9,#0xf80000000 → mov x9,#0x100000000
- **function-matched** (`main` of builds without CUTS): engine region 62 GB → 4 GB (11 instructions in four functions): 4 functions, 11 cuts

### Taiko Risshiden V DX

[Taiko Risshiden V DX](../../dm/games/0100346017304000/README.md), `0100346017304000`, [patches.py](../../dm/games/0100346017304000/patches.py).

- **`game`**, frame rate, at goal, checked: MATCH_CUTS enrolled on both builds: KTGL frame limiter threshold: 0 at one vsync a frame. Function-matched over its two builds (MATCH_CUTS); whether Age of Calamity, Three Houses or ROMANCE OF THE THREE KINGDOMS 8 REMAKE share the function is unchecked (an engine rule if they do)

- **1.1.1 `main`** `f5ab74b9…` ([patches.py:15](../../dm/games/0100346017304000/patches.py#L15))
  - cut `+0x443fac`: frame limiter threshold: N × tick frequency / 60 (umulh by 1/60 → udiv by 60), then 0 when N = 1 (cmp w20, #1; csel x20, xzr, x8, eq): one vsync a frame is the present pacing's; N = 2 keeps the 2 ms rounds
- **function-matched** (`main` of builds without CUTS): frame limiter threshold: 0 when N = 1: 1 function, 1 cut
- **function-matched** (`main` of builds without CUTS): frame limiter threshold: 0 when N = 1: 1 function, 1 cut

### The Legend of Zelda: Breath of the Wild

[The Legend of Zelda: Breath of the Wild](../../dm/games/01007EF00011E000/README.md), `01007EF00011E000`, [patches.py](../../dm/games/01007EF00011E000/patches.py).

- **`build` → `game`**, frame rate, gap, judgement: interval controller: the lower bound and the GPU-time path. Sead::GameFrameworkNx's interval controller in this build; Tears of the Kingdom shares sead but not this code
- **`build` → `game`**, frame rate, blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several, judgement: 60 fps frame step and render scale (ksys::VFR). The game's own frame code; the frame-step state page is general

- **1.9.0 `main`** `cd57b23f…` ([patches.py:14](../../dm/games/01007EF00011E000/patches.py#L14))
  - cut `+0x112670c`: lower bound of the candidate interval: fmov s0,s11 (2.0) → fmov s0,s10 (1.0)
  - cut `+0x1126710`: lower bound of the candidate interval: cmp w27,#2 → cmp w27,#1
  - cut `+0x112665c`: step-down target recorded when stepping up, max(candidate, w24) − 1: mov w24,#3 → mov w24,#2
  - cut `+0x1126748`: step-down target recorded when stepping up: cmp w8,#3 → cmp w8,#2
  - cut `+0x1126794`: stepping down stops at < 3 → at < 2: cmp w9,#3 → cmp w9,#2
  - cut `+0x112691c`: interval controller always takes the GPU time path (CPU span timing): cbz x0,#0x1126934 → b #0x1126928
  - cut `+0x1126974`: interval controller always takes the GPU time path (takes max(CPU span, GPU time)): cbz x0,#0x112698c → b #0x1126980
  <details><summary>43 frame-step sites</summary>

  - frame step `+0x27ae0`: Pane::Calculate: a HUD widget at the edge moved to the taller screen's edge with its children, full-screen backgrounds stretched (duo_anchor.c)
  - frame step `+0x2df28`: projected texture fitted to the layout: a pane as tall as the taller screen maps its whole height
  - frame step `+0xc61ef4`: output size static, nnMain: 1920x1080 → the host's height
  - frame step `+0xc61f28`: output size static, nnMain (second path)
  - frame step `+0xc61f5c`: layout size static, nnMain: 1280x720 → the host's layout height
  - frame step `+0xde85dc`: 720.0 with 1280.0 (screen position in layout space)
  - frame step `+0xdea070`: 720.0 with 1280.0 (screen position / layout size)
  - frame step `+0xdea678`: 720.0 with 1280.0
  - frame step `+0xdf19ac`: 720.0: output size / layout size (the layout scale)
  - frame step `+0xe27b44`: 720.0 stored with 1280.0
  - frame step `+0xeb0f88`: held-button counts step by the VFR ratio (menu repeat in game time at any frame step)
  - frame step `+0xeb48b8`: sead::PerspectiveProjection fovy widened for a view of the screen's ratio (more above and below, 16:9 sides), stored widened
  - frame step `+0xeb4968`: sead::PerspectiveProjection fovy widened for a view of the screen's ratio (more above and below, 16:9 sides), stored widened
  - frame step `+0xeb49d0`: sead::PerspectiveProjection fovy widened for a view of the screen's ratio (more above and below, 16:9 sides), stored widened
  - frame step `+0xeb4a50`: PerspectiveProjection matrix: the HUD camera (16:9, near 1, far 10000) takes the screen's ratio and a widened vertical angle
  - frame step `+0xef1388`: 1280x720 in a descriptor
  - frame step `+0xf59b2c`: capture pane Calculate: a full-screen capture made as tall as the screen (duo_anchor.c)
  - frame step `+0xf5a0dc`: capture: the screen's layout height instead of the layout file's 720 (texture size, copied rect)
  - frame step `+0xf5a4b8`: capture: the screen's layout height instead of the layout file's 720 (texture size, copied rect)
  - frame step `+0xf60cc0`: capture pane Calculate: a full-screen capture made as tall as the screen (duo_anchor.c)
  - frame step `+0xf66118`: capture: the screen's layout height instead of the layout file's 720 (texture size, copied rect)
  - frame step `+0xf66334`: capture: the screen's layout height instead of the layout file's 720 (texture size, copied rect)
  - frame step `+0xf6e798`: 720.0 with 1280.0 (screen position)
  - frame step `+0xf75ba4`: screen copy into a 16:9 picture (camera photo): the screen's middle 16:9 band, not the whole taller screen squashed into it
  - frame step `+0x100817c`: 720.0 with 1280.0 passed as a layout size
  - frame step `+0x1059730`: 1280x720 layout size of an object
  - frame step `+0x106bb6c`: 1280x720 default sizes of a layer
  - frame step `+0x10ee094`: main camera fovy getter: widened like the projection (culling tests)
  - frame step `+0x10ee0cc`: main camera fovy getter in degrees: widened like the projection
  - frame step `+0x11269b8`: setWaitVsyncInterval: the host's step unless the VFR override is set (state page target fps; 0 = the game's interval)
  - frame step `+0x12618c4`: output size static, its getter
  - frame step `+0x1261920`: layout size static, its getter
  - frame step `+0x12660d4`: docked display size 1920x1080
  - frame step `+0x12660f0`: docked viewport height 1080
  - frame step `+0x1266124`: handheld display size 1280x720
  - frame step `+0x1266134`: scaled display height 720.0
  - frame step `+0x1266188`: handheld viewport height 720
  - frame step `+0x126686c`: scale apply block taken every frame when the host render scale is not 1.0
  - frame step `+0x1266880`: 3D view scale = the host render scale (1.0 = the game's dynamic resolution)
  - frame step `+0x127a2f8`: map footprint trail: its viewport and projection at the 720 pane's half-height, not the taller frame's
  - frame step `+0x13f9704`: 1280x720 passed as a size
  - frame step `+0x151d3d0`: VFR::updateInterval: its own override published for the host (state page target fps; 0 = original)
  - frame step `+0x1544644`: 720.0 with 1280.0

  </details>

  - render scale stub (the launcher offers DM_RENDER_SCALE)

### The Legend of Zelda: Link's Awakening

[The Legend of Zelda: Link's Awakening](../../dm/games/01006BB00C6F0000/README.md), `01006BB00C6F0000`, [patches.py](../../dm/games/01006BB00C6F0000/patches.py).

- **`build` → `game`**, race, gap, judgement: PhysX completion task release. A lifetime race in the game's own completion task (its release slot serves this one vtable)

- **1.1.0 `main`** `909e904a…` ([patches.py:12](../../dm/games/01006BB00C6F0000/patches.py#L12))
  - cut `+0x10cd070`: physics completion task release (calls its own destructor): ldr x8,[x0] → ret (no longer destroyed; the step function rebuilds it in place every step)

### The Legend of Zelda: Ocarina of Time

[The Legend of Zelda: Ocarina of Time](../../dm/games/0400486024DEC000/README.md), `0400486024DEC000`, [patches.py](../../dm/games/0400486024DEC000/patches.py).

- **`game`**, frame rate, at goal, checked: v131072 main: one function with this fingerprint, the site and its free registers read by disassembly (2026-11-08): frame ratio from the host's step. The game's own frame-ratio division, found by its function's fingerprint on any build that keeps the function
- **`game`**, rendering, at goal, checked: v131072 main: one function with this fingerprint (a leaf, x16 / x17 free), its callers and the controller read by disassembly (2026-11-08): dynamic resolution held at full size. The game's own dynamic-resolution level function, found by its function's fingerprint on any build that keeps the function; switchable (DM_DYNAMIC_RESOLUTION)

- **function-matched frame step** (`main` of builds without FRAME_STEP): frame ratio from the host's step: a function of 0x9b4 bytes, `+0xe4` in it; dynamic resolution, a function of 0x294 bytes, `+0x0` in it; launcher capabilities: DYNAMIC_RESOLUTION

### The Legend of Zelda: Tears of the Kingdom

[The Legend of Zelda: Tears of the Kingdom](../../dm/games/0100F2C0115B6000/README.md), `0100F2C0115B6000`, [patches.py](../../dm/games/0100F2C0115B6000/patches.py).

- **`build` → `game`**, frame rate, blocked: a function-matched frame step (MATCH_FRAME_STEP) covers one function; these stubs span several, judgement: 60 fps frame step and render scale. The game's own timing object

- **1.4.3 `main`** `277178b7…` ([patches.py:136](../../dm/games/0100F2C0115B6000/patches.py#L136))
  - frame step `+0xd5cc0`: view render size x the host render scale (1.0 = original)
  - frame step `+0xd5d80`: dynamic resolution only at render scale 1.0
  - frame step `+0x1fbc80`: D-pad menu fade starts at full rate under fractional steps (FPSLocker)
  - frame step `+0x2daa54`: game step reads the float fps (original integer fps and scvtf when off)
  - frame step `+0x2daa6c`: scvtf moved into the stub at the load
  - frame step `+0x2db18c`: frame step from the host in whole vsyncs, by elapsed time until it has decided one (state page target fps; 0 = original interval logic)
  - frame step `+0x3e562c`: game step reads the float fps (original integer fps and scvtf when off)
  - frame step `+0x3e5638`: scvtf moved into the stub at the load
  - frame step `+0xbe14a8`: swapchain argument 1 when on (FPSLocker)
  - render scale stub (the launcher offers DM_RENDER_SCALE)

### Xenoblade Chronicles 3

[Xenoblade Chronicles 3](../../dm/games/010074F013262000/README.md), `010074F013262000`, [patches.py](../../dm/games/010074F013262000/patches.py).

- **`build` → `game`**, address space, gap, judgement: malloc region 60 GB → 4 GB and its first arena. Monolith's own allocator; its constants span two functions (a multi-function rule). The cause, an iPhone's address space, is a platform limit

- **2.2.1 `main`** `82d187fe…` ([patches.py:16](../../dm/games/010074F013262000/patches.py#L16))
  - cut `+0x128e58c`: malloc address region: 60 GB to 4 GB
  - cut `+0x1241870`: first arena bump size, low part: mov x9,#0xffff
  - cut `+0x1241880`: first arena bump size: 512 MB + 128 KB + 64 KB - 1
  - cut `+0x12418d8`: first arena subtraction, sign extension
  - cut `+0x12418dc`: first arena subtraction: -(512 MB + 128 KB)
  - cut `+0x12418e8`: first arena stored capacity: 512 MB + 128 KB

## SDK cuts

Cuts of Nintendo SDK `sdk` builds ([sdk_patches.py](../../dm/tools/sdk_patches.py)), applied to every game that ships the build. They fit the SDK's address-space layout into an iPhone's guest block. The games listed are those whose profile registers the build.

- **`sdk`**, address space, at goal, checked: 20 registered builds rewritten byte-identical with the rules alone, 2026-10-29 and 2026-10-30; the 2 MB alignment on every sdk build on the drive, 2026-10-30: node area 1 GB → 62 MB and regions of 4 MB and more aligned to 2 MB, as SDK 20: the SDK-wide rules. One rule per reviewed implementation; every sdk build without CUTS gets them
- **`build` → `sdk`**, address space, blocked: the games that reach them (Pokémon Brilliant Diamond, Monster Hunter Rise, 13 Sentinels: Aegis Rim; Brain Memory Training Academy; Ace Attorney Investigations Collection) have no Mac build: run one per build with the alignment cuts, checked: the rules resolved on each build's sdk, 2026-10-29 and 2026-10-30: rows the rules would add the alignment cuts to (2d369d99, 12f16103, 311deab1). The rules give these builds the same node area cut and the three alignment cuts more; each row keeps the alignment out
- **`build` → `sdk`**, address space, blocked: no copy on the drive to compare, judgement: rows of builds not on the game drive (56ec2474, 9c73fb73, e01950c5). Likely what the rules give (each names one of their implementations)
- **`build` → `sdk`**, address space, blocked: one game ships it, judgement: VammManager node area and alignment, SDK 4.4.0 (9de92bad). An older implementation no rule covers (its large regions aligned to 32 MB, not the rules' 2 MB); a rule once a second game ships it

- **sdk** `9de92bad…` ([sdk_patches.py:9](../../dm/tools/sdk_patches.py#L9)): Mario + Rabbids Kingdom Battle 1.9.589692
  - cut `+0x93dfc`: VammManager node area limit: 1 GB to 64 MB
  - cut `+0x93e8c`: VammManager occupied node area: 1 GB to 64 MB
  - cut `+0x93fe0`: AllocateAddressRegion: align regions of 1 GB and more to 32 MB
- **sdk** `2d369d99…` ([sdk_patches.py:18](../../dm/tools/sdk_patches.py#L18)): 13 Sentinels: Aegis Rim (Asia) 1.00, 13 Sentinels: Aegis Rim 1.10, Big Brain Academy: Brain vs. Brain 1.2.0, Mario Party Superstars 1.1.1, Metroid Dread 2.1.0, Monster Hunter Rise 16.0.2, Pokémon Brilliant Diamond 1.3.0
  - cut `+0x34e0c8`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x34e164`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000
- **sdk** `56ec2474…` ([sdk_patches.py:27](../../dm/tools/sdk_patches.py#L27)): Fire Emblem Engage 2.0.0
  - cut `+0x346430`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x3464cc`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000
- **sdk** `311deab1…` ([sdk_patches.py:35](../../dm/tools/sdk_patches.py#L35)): Ace Attorney Investigations Collection 1.0.0.2, ROMANCE OF THE THREE KINGDOMS 8 REMAKE 1.1.3
  - cut `+0x139468`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x1394fc`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000
- **sdk** `12f16103…` ([sdk_patches.py:43](../../dm/tools/sdk_patches.py#L43)): Brain Memory Training Academy 1.0.0, Unicorn Overlord (Asia) 1.05, Unicorn Overlord 1.05
  - cut `+0x134778`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x13480c`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000
- **sdk** `9c73fb73…` ([sdk_patches.py:50](../../dm/tools/sdk_patches.py#L50)): Patrick's Parabox 1.0.1
  - cut `+0x37c3b0`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x37c44c`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000
- **sdk** `e01950c5…` ([sdk_patches.py:58](../../dm/tools/sdk_patches.py#L58)): Hollow Knight: Silksong 1.0.30000
  - cut `+0x145bfc`: AddressRegionManager constructor: node area limit mov w8,#0x3fe00000 → mov w8,#0x3e00000
  - cut `+0x145c68`: AddressRegionManager constructor: length of the node area registered as an occupied region mov w9,#0x3fe00000 → mov w9,#0x3e00000

### SDK-wide function-matched rules

Applied to the `sdk` of any build without CUTS, found by function fingerprint ([function-matched cuts](../reference/rewriter.md#function-matched-cuts-for-unregistered-builds)):

- node area 1 GB → 62 MB: SDK 7.3.2 (DRAGON QUEST XI S), 8.2.1 (Super Smash Bros. Ultimate), 8.3.1 (Paper Mario: The Origami King)
- node area 1 GB → 62 MB: SDK 10.4.1 (Advance Wars 1+2), 10.4.8 (Pikmin 4)
- node area 1 GB → 62 MB: SDK 11.4.3 (Pokémon Brilliant Diamond), 12.3.2 (OCTOPATH TRAVELER II), 12.3.9 (Xenoblade Chronicles 3), 13.3.5 (Mario + Rabbids Sparks of Hope), 14.3.0 (Batman: Arkham Knight)
- node area 1 GB → 62 MB: SDK 15.3.2 (Paper Mario: The Thousand-Year Door), 16.2.0 (Sea of Stars), 16.2.4 (Brain Memory Training Academy), 17.5.3 (Ace Attorney Investigations Collection), 18.3.2 (Absolum), 18.3.5 (Super Mario Galaxy)
- node area 1 GB → 62 MB: SDK 19.3.11 (Pokémon Legends: Z-A), 19.3.13 (Octopath Traveler 0), 20.5.19 (BALL x PIT), 20.5.22 (Tears of the Kingdom)
- node area 1 GB → 62 MB: SDK 22.2.0 (EA SPORTS FC 27, Well Dweller): the SDK 19 / 20 constructor, instruction for instruction up to its cold path, which gives each failing result its own abort (32 bytes more)
- node area 1 GB → 62 MB: SDK 22.2.0 built for the Switch 2 (Fire Emblem Fortune's Weave): the constructor at sdk+0x16ba30 with return address signing and its own frame. The host's StandardAllocator cap counts on the 62 MB (alias_room): with 1 GB the capped region did not fit the alias region
- node area 1 GB → 62 MB: SDK 19.3.3 (Mario Kart World), 20.5.15 (Yoshi and the Mysterious Book, Hyrule Warriors: Age of Imprisonment), 20.5.19 (Donkey Kong Bananza) built for the Switch 2: the constructor at sdk+0x14df00 on 20.5.15, with return address signing. Unreal's engine region takes what the alias region has room for, counting on the 62 MB (alias_room): with 1 GB nninitStartup's AllocateAddressRegion fails and it exits
- regions of 4 MB and more aligned to 2 MB, as SDK 20: SDK 7.3.2 (DRAGON QUEST XI S), 8.2.1 (Super Smash Bros. Ultimate), 8.3.1 (Paper Mario: The Origami King), 10.4.1 (Advance Wars 1+2), 10.4.8 (Pikmin 4)
- regions of 4 MB and more aligned to 2 MB, as SDK 20: SDK 11.4.0 (Pokémon Legends: Arceus, Kirby and the Forgotten Land): the next rule's size classes with 8 more bytes of body; the 4 GB StandardAllocator region of Arceus's nninitStartup (the host's cap) fits after the 62 MB node area only with it
- regions of 4 MB and more aligned to 2 MB, as SDK 20: SDK 12.3.2 (OCTOPATH TRAVELER II), 12.3.9 (Xenoblade Chronicles 3), 13.3.5 (Mario + Rabbids Sparks of Hope), 14.3.0 (Batman: Arkham Knight), 15.3.2 (Paper Mario: The Thousand-Year Door)
- regions of 4 MB and more aligned to 2 MB, as SDK 20: SDK 16.2.0 (Sea of Stars), 18.3.2 (Absolum), 18.3.5 (Super Mario Galaxy)

## Translator rules keyed by a shader's code

- [Program.cs:259](../../dm/gfx/tools/dmsh_xlate/Program.cs#L259): Tears of the Kingdom 1.4.3 visibility counter (one vertex shader, exact code SHA-256 below) (**`game` → `host`**, gap: a general lowering of subgroup ballots in vertex shaders would cover any shader that counts that way)

## Profile switches

Profile keys (`game.tsv`) whose value changes what the host does, set away from their default ([keys](../../dm/games/README.md)); the rarest first. Sizes, layouts and the controller layout are left out.

| Key and value | Games | Binding | Why |
|---|---|---|---|
| `programs 1=010049900F546001 2=010049900F546002` | [Super Mario 3D All-Stars](../../dm/games/010049900F546000/README.md) | `game`, at goal | which programs a game has that this host can run: a fact of its files, the profiles that exist for them |
