Files
seedds 3a993fa3fe Subsystem references and a symptom index: the failure catalogue of docs/agents/03-bringup.md and the per-title material of docs/agents/04-graphics.md (section 1's container list, section 6 and its "Seen in <game>" subsections) move into docs/reference/, one heading per mechanism: rewriter.md, memory.md, threads.md, services.md, movies.md, audio.md, frame-rate.md, nvn-objects.md, rendering.md (with the Vulkan and OpenGL layers), shaders.md and game-state.md, indexed by docs/reference/README.md. Each entry gives the symptom, the cause, the fix (file and function), the games it was found on (linked to their notes in dm/games/<id>/README.md) and any check, caveat or later change; one mechanism met on several games is one entry. docs/agents/symptoms.md lists every entry's symptom (an assertion, a [RED] line, an abort or crash site, a visible result) with a link to it, 350 lines, generated from the Symptom bullets. 03 keeps the loop and reading the log, and its Failure catalogue section now points to the references, the index and where a new finding goes; 04 keeps sections 1-5 and 7 (the container list is shaders.md's Containers by engine), and section 6 says where each kind of finding is. Facts in the old sections about one game only were checked against that game's note, where they already were. Statements the code no longer matches are marked as history beside the current value (movie output slots: MD_NOUT 64, MD_NOUT_AAC 32, MD_NOUT_VIDEO 16; APP_POOL is the profile key app_pool; Engage's layout is 5 / 4.375 GB; inline uniform updates are deferred by default; scaled copies are drawn), and Tears of the Kingdom joins the node-area entry's build list (issue #70). The game notes, docs/agents/README.md, 02 and 05 link to the exact entries, and so do the comments in nvn_mtl.m (nvnTextureCompare) and hle_audio.c (the RemoteIO buffer) and the provisional-profile note in profile_guess.py. 03 goes from 29,600 to 470 words, 04 from 34,400 to 3,500. Checked: every backticked span, module address, issue / PR number and 16-digit hash of AGENTS.md, development.md, dm/games/README.md and docs/agents/01-05 at 6a06877 (4,600 items) still appears in the repository's Markdown (the same five file patterns as before appear as the full names they stood for), every relative link and heading anchor in the repository's Markdown resolves, and the tool tests pass (the four that need capstone or lz4 in the T7 venv)
2026-10-25 12:31:58 +08:00
..
Subsystem references and a symptom index: the failure catalogue of docs/agents/03-bringup.md and the per-title material of docs/agents/04-graphics.md (section 1's container list, section 6 and its "Seen in <game>" subsections) move into docs/reference/, one heading per mechanism: rewriter.md, memory.md, threads.md, services.md, movies.md, audio.md, frame-rate.md, nvn-objects.md, rendering.md (with the Vulkan and OpenGL layers), shaders.md and game-state.md, indexed by docs/reference/README.md. Each entry gives the symptom, the cause, the fix (file and function), the games it was found on (linked to their notes in dm/games/<id>/README.md) and any check, caveat or later change; one mechanism met on several games is one entry. docs/agents/symptoms.md lists every entry's symptom (an assertion, a [RED] line, an abort or crash site, a visible result) with a link to it, 350 lines, generated from the Symptom bullets. 03 keeps the loop and reading the log, and its Failure catalogue section now points to the references, the index and where a new finding goes; 04 keeps sections 1-5 and 7 (the container list is shaders.md's Containers by engine), and section 6 says where each kind of finding is. Facts in the old sections about one game only were checked against that game's note, where they already were. Statements the code no longer matches are marked as history beside the current value (movie output slots: MD_NOUT 64, MD_NOUT_AAC 32, MD_NOUT_VIDEO 16; APP_POOL is the profile key app_pool; Engage's layout is 5 / 4.375 GB; inline uniform updates are deferred by default; scaled copies are drawn), and Tears of the Kingdom joins the node-area entry's build list (issue #70). The game notes, docs/agents/README.md, 02 and 05 link to the exact entries, and so do the comments in nvn_mtl.m (nvnTextureCompare) and hle_audio.c (the RemoteIO buffer) and the provisional-profile note in profile_guess.py. 03 goes from 29,600 to 470 words, 04 from 34,400 to 3,500. Checked: every backticked span, module address, issue / PR number and 16-digit hash of AGENTS.md, development.md, dm/games/README.md and docs/agents/01-05 at 6a06877 (4,600 items) still appears in the repository's Markdown (the same five file patterns as before appear as the full names they stood for), every relative link and heading anchor in the repository's Markdown resolves, and the tool tests pass (the four that need capstone or lz4 in the T7 venv)
2026-10-25 12:31:58 +08:00

Super Smash Bros. Ultimate (01006A800016E000)

Update 13.0.5 (v2031616) over the base game, with its 99 DLC licences; SDK 8.2.1. Bandai Namco / Sora's engine (namespaces app, lib, phx, nu) on NVN. Modules main, subsdk0 (NintendoSDK_movie) and sdk, the same sdk and movie builds as Catherine: Full Body (0100BF00112C0000); the fighters' code is 98 NRO modules loaded at run time. Plays on the iPhone (IPA 17.5 GB; offline). On the Mac: the opening movie, the title, the first launch's DLC unlocks and Challenges board, the main menu, the Smash rulesets, stage select, fighter select, 2-player battles (Frigate Orpheon, Big Blue, Great Bay, Find Mii) at 60 fps with about 2.7 ms of GPU per frame and 2 GB resident (1.2 GB of Metal allocations), quitting a battle to its results and a second battle whose fighters' NROs the game loaded again.

What it needs

Setting Where Why
Engine region 62 GB → 4 GB (11 instructions) patches.py, main 21450c64… the game aborts in its static initialisers when its 62 GB address region fails; see Memory
Node area 1 GB → 62 MB, regions of 1 GB and more aligned to 32 MB dm/tools/sdk_patches.py, sdk build 5fd4f531… (sdk+0x336b50 / +0x336bf0, +0x336d5c) with them the cut region starts 64 MB into the alias region instead of 1.95 GB
5 GB guest layout: mem_reserve 0x140000000, mem_alias 0x118000000, mem_stack 0x10000000, app_pool 0xCD500000 game.tsv a 4.375 GB alias region, where the game maps its memory itself
sys_resource 0x1000000 game.tsv the NPDM declares 16 MB of system resource (virtual address memory); main never sets a heap
NRO modules dm/tools/nro_collect.py (nro.tsv), loader.c "NRO modules", hle_ro.c, gen_embed.py the fighter, item and common scripts; see Fighter code at run time

No pad_layout key (the iPhone pad starts in the 3D layout).

Memory

  • Resolved: an abort in the static initialisers, before nnMain (main+0x37c9bd0), when the engine's own 62 GB address region failed. The engine's memory (the nu:: allocator behind nu::VirtualAllocHook, set up by a static constructor at main+0x37c9a20) reserves 62 GB with nn::os::AllocateAddressRegion(0xf80000000) (main+0x37c9a5c) and hands it out in 64 KB units: a number line of free ranges, first [0, 0xf7f20) units from the region's start (main+0x37c9b98, given to main+0x37c9c00), and the top 14 MB (region + 0xf7f200000) as the pool of its range nodes, committed 64 KB at a time up to the region's end (the bound checks at main+0x37c9a9c, +0x37c9c50, +0x37ca3cc and +0x37caf68). The size, the header offset, the page count and three region-end bounds all follow from 62 GB, so patches.py cuts all 11 instructions to a 4 GB region (the node pool at 4 GB − 14 MB, the first free range 0xff20 units); the application pool (3.2 GB) bounds what it can commit.
  • Booted once with a 64 GB alias region (mem_reserve 0x1030000000, mem_alias 0x1008000000) and DM_SVC=1's map log: the game commits from the region's start upward (1.73 GB contiguous at the title, 75 s in) and its page tables (the node pool) from the top; a battle commits up to 2.5 GB (DM_ALIAS_WINDOWS).
  • The cut region still did not fit: SDK 8 has the same 1 GB node area and 1 GB alignment of regions of 1 GB and more as the newer SDKs (constructor sdk+0x336b40, orr w9, wzr, #0x3fe00000 at +0x336b50 / +0x336bf0; VammManager::AllocateAddressRegion's alignment at +0x336d5c); with them it started 1.95 GB into the alias region (measured with a 64 GB one). They are cut in sdk_patches.py as on DRAGON QUEST XI S's SDK 7.3.2 build (01006C300E9F0000), whose AddressRegionManager this is at other offsets; the region then starts 64 MB into the 4.375 GB alias region of the 5 GB block.

Fighter code at run time

  • Resolved: the frame loop ran, but the game waited for code it loads itself (ro::RegisterModuleInfo / ro::GetBufferSize red lines). main imports 1,045 lua2cpp::create_agent_* functions, global, that no ExeFS module defines, bound to stubs at start. The fighter, item and common scripts are 98 NRO modules in data.arc (prebuilt:/nro/release/lua2cpp_<name>.nro, 193 MB), registered by .nrr/cross2_*.nrr. The game loads them with nn::ro::LoadModule as fighters appear (common and item at boot, the opening movie's fighters, each battle's) and unloads them after.
  • Current: they are collected at pack time by the SHA-256s the NRRs list (dm/tools/nro_collect.py, among data.arc's current files; the NRRs of older releases also register 666 superseded copies, which data.arc still holds and which are left out), rewritten like any module and loaded by the host, which binds main's lua2cpp stubs to them. 87 need no rewrite at all, 11 have one x18 site each. The game loads six NROs in its first 30 s and calls none of the stubs.
  • On iOS they are packed into three sections of the executable (gen_embed.py: __dm_nro_x0, __DM_NRO_W, __dm_nro_x1, and a table of their pieces, __dm_nro_tab), 157 MB of code; a Mach-O file has at most 255 sections, and three per NRO would pass it (loader.c nro_pieces). Played on an iPhone.

Rewriter

  • Resolved: an unhandled jump table, its far base passed through other registers (main+0x2b74458: ldrb w18,[x14]; sub w18,w18,#1; cmp w18,#6; b.hi; ldrsw x18,[x7,x18,lsl #2]; add x18,x18,x7; br x18). x7 is built by adrp + add 688 instructions before, then parked in x30 around a loop (mov x30,x7 … mov x7,x30), so the far chain met a mov and stopped; the function-wide search found a second adrp x7 + add pair (another table further on) whose seven targets also lie in the function. It was that main's only unhandled site; Smash's sdk and movie module come out byte-identical with the fix.

Services

  • Resolved: a jump to pc=0 right after the NVN bootstrap loader (lr=main+0x37fe930, [RED] NVN address lookup of an unknown name: nvnSetExternalDebuggerEnabledNVX). The game fetches an NVX extension of the SDK 8 driver by name and calls it without checking the pointer. The real driver has it, so it joins dm/gfx/nvn/names.txt as a no-op (thunks regenerated with gen_protos.py; no prototype in nvn.h, so NVN_NOPROTO).

Rendering

  • Resolved: a pink window, every command buffer ignored, while headless runs looked right (DM_WINDOW=1). The first presents failed on the display command buffer with kIOGPUCommandBufferCallbackErrorPageFault, and after a few of those macOS ignored every submission of the process ("Ignored (for causing prior/excessive GPU errors)"). The game presents its window texture in its first frames before drawing into it; the texture was made on that first resolution in the present path and added to the residency set (res_add), but only a submission commits the set, so the display command buffer sampled a texture outside the committed set. Headless runs never present, which is why they looked right.

Files and shaders

  • The RomFS is one data.arc (17.6 GB; the profile's romfs_marker) beside 14 NRRs. Its header (magic 0xABCDEF9876543210) gives the offsets of the music, file and shared-file sections and of the file system table (one zstd frame of 50 MB); paths are Hash40s (CRC-32 of the path, its length in the top byte). A path leads to its current file through its info index, file info, info-to-data entry and file data, at file section + directory offset + 4 × its offset, zstd or stored (dm/gfx/tools/smash_arc.py documents the layout) (01, Compressed RomFS content).
  • The archive also keeps every earlier version of updated files, which no path leads to any more: 183,882 data blobs, 169,939 of them current (the 98 fighter NROs, 764 with their old versions, which the NRRs of older releases still list). A file's first bytes name its format: SSBH HBSS resources (RDHS shader databases, XFUN effect libraries, LDOM / HSEM / LTAM / MINA / LEKS models, meshes, materials, animations, skeletons), EFFN effects, SARC UI layouts, BNTX, NUS3 sound and the NROs (NRO0 at +0x10).
  • Shaders: 35,012 (22,197 vertex, 12,761 pixel, 53 compute, 1 geometry): GLSLC outputs in the 41 SSBH shader databases (.nushdb, 7,764), BNSH in the effects (EFFN, 26,419) and UI layouts (SARC, 752), and 77 in main. The split reads data.arc's current files (shader_split.py smash_arc_jobs).

Mac routes

  • The work folder's run/ctl.sh drives a run started with DM_CTL (run/step.sh <log> <shot> <frames> <presses…> presses, waits on the frame counter and takes a shot).
  • From run/save_ref (past the first launch): A skips the movie, A at the title reaches the main menu, A (Smash), A (a ruleset), A (Random stage), then at the fighter select (after its "Joined!" banner) LUp~0.85, LLeft~0.85, LDown~0.3, LRight~0.4 lands on Mario, A, Plus.

Found on this game

General host changes first needed here; each applies to every game:

Open

  • The one geometry shader among the 35,012: whether it builds is not recorded.