Commit Graph
23 Commits
Author SHA1 Message Date
Deon FoucheandClaude Opus 5.5 f7d563db05 Draw Xbox button icons into the prompts overlay with make_romfs_patches.py --prompts
tools/button_icons.py, adapted from MacNativeGames' make_button_icons.py, draws LB, RB, LT, RT, Menu, View and a d-pad
cross into the button font of every font archive and into the button guide's L and ZL images, with the letters cut out
in the game's own text fonts, and raises the resource size table for the archives that grow. --prompts xbox swaps the
face buttons as --xbox-prompts did (now its older name); --prompts xbox-label keeps their letters for the xbox and auto
pad layouts. The plain overlay is unchanged. tests/romfs_prompts_test.py runs both on a RomFS it builds itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 20:50:17 +10:00
Pasha Kagan 3c749df3f4 Test tools/pack_shader_cache.py on a fake shader cache 2026-10-31 07:23:40 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a76224f8a6 Fail the install when romfs/ is gone or unreadable after cleanup
An install whose romfs/ went empty and unreadable after the extraction had verified it (a folder Windows was still
deleting) ended with result ok, and the game stopped at its first file read. Cleanup now checks that romfs.bin and
index.json are still there, match the verified size and hash record, and that romfs.bin opens; otherwise it fails with
cleanup.romfs_unreadable, which tells the player to restart Windows and run the installer on the same folder (resume
extracts the game data again). Reported in #107.

tests/installer_test.py CleanupTest: an emptied, removed or resized romfs passed cleanup before, fails now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:42:03 +03:00
Valiantsin DzerakhandClaude Opus 5.5 67116a387f Map the zh-CN and zh-TW game languages to zh-Hans and zh-Hant
Choosing Simplified Chinese in the installer wrote lang = zh-CN to totk.ini and the game showed Japanese: ov_language() handed the code to nn::oe::GetDesiredLanguage unchanged, and TotK only accepts zh-Hans and zh-Hant for Chinese. Reported in #72 and #68.

ov_language() now maps both old spellings, so existing totk.ini files keep working and cfg.c still accepts them. The F1 menu offers one row per language under the canonical codes. The installer lists only zh-Hans and zh-Hant, writes them, and reads zh-CN or zh-TW from the CLI or from a recorded totk-install.json as the canonical code, so a repair or update of an old install does not fail with check.lang_unknown and rewrites the ini. --probe-services prints the configured language and checks the four Chinese codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 13:27:19 +03:00
Valiantsin DzerakhandClaude Opus 5.5 758b46460f Keep the regression routes and the input scripts made for the maintainer's own saves out of the repository: regress.py, its scoring and test, and the fight, island and backrun scripts work only with those saves; load_save.txt stays as run_game.py's default
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 13:12:53 +03:00
Valiantsin DzerakhandClaude Opus 5.5 c2943970cc Merge the spin wait gates: they also end the fight hangs
The generator emits a guest poll such as `ldr w9, [x19]; cmp w9, #1; b.eq` as a plain C load, and clang hoists it out
of the loop: the lock wait in f_7001fa0e2c compiled to `cmp; jne; jmp .`, so a thread that found the lock held spun
forever after its holder released it. A fight run hung this way in 3 of 13 launches on an RX 9070, with the UBO
snapshot on and off; gdb showed the thread on that `jmp` in every sample. The gate is an opaque call on every
back-edge of the 868 loops tools/spin_waits.py lists, so each pass reloads memory: the exe goes from 182 self-jumps to
148, and 144 of those are the game's own `b .` instructions. 8 of 8 fight runs then passed; tests/diff/func.py with
--patches passed 5470 cases on 878 functions, and the four probes passed on 1.4.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:05:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2fe6a6d4c1 Keep MXCSR in line with FPCR where FPCR changes instead of checking it in every FP op
The FP helpers compared c->fpcr with a cached copy before every operation to resync MXCSR lazily. MXCSR now
follows FPCR.FZ at once: MSR FPCR calls rt_fpcr_sync, and so do rt_call (thread, fiber and host entry into guest
code), fiber resume (FIBER_FLAG_FLOAT_SWITCH fibers keep their own MXCSR) and the differential test harness per
case. op and vop only test FPCR.RMode for the slow path, and their redo check is one ordered-not-equal compare of
|r| with the smallest normal, the same NaN-or-smallest-normal set as before.

Hot guest code shrinks by about a quarter (132 functions holding half the guest cycles, 1.4.3); fight frame time
moves 1-3%, inside the run-to-run spread. lift, simd, func, atomic and flags_check pass on 1.4.3; simd.py fails
without the harness sync.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 12:25:25 +03:00
Valiantsin DzerakhandClaude Opus 5.5 27056b212a Keep NZCV in a local of each generated function instead of c->nzcv
Every flag-setting instruction packed N, Z, C and V into c->nzcv and every reader unpacked them. recomp/flags.py
now runs a reaching-definitions pass per function: a compare stores its operands in a local Flags F, and a reader
whose definitions are all of one kind computes its condition from them, so cmp and b.cond become one host compare.
CCMP, FCMP, MSR NZCV and ADCS write the packed form, which readers reached by several kinds also use. Calls and
returns publish nothing (AAPCS64 neither passes nor preserves NZCV); tail branches, falls into the next function and
br through rt_dispatch publish c->nzcv, since discovery can start a function inside another one. Functions with an
unresolved computed br keep flags in c->nzcv.

1.4.3 main: 492k direct and 89k packed flag reads, .text 342 -> 299 MiB. Fight bench (bench-fight2-2026-10-27b,
frames 5400-7500, uncapped) 13.15 and 13.63 ms vs 13.9 before. tests/flags_check.py checks the new helpers against
the packed ones; tests/diff/func.py no longer compares NZCV, which generated code leaves untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:07:58 +03:00
Valiantsin DzerakhandClaude Opus 5.5 e9216b8b49 Test functions with calls in tests/diff/func.py: every BL and BLR goes to one stub on both sides, which folds the registers at the call into a digest kept in the scratch buffer and sets X0-X18, NZCV and V0-V7 from it, so a register missing from the Cpu at a call or held across one fails the case
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:12:34 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3984344635 Spin wait gates: tools/spin_waits.py (the nxnative search) lists the loops that only another thread can end, the patch tables carry them as spin lines (857 in 1.4.3, 864 in 1.2.1), the generator sends their back-edges through rt_spin_gate, and the gate pauses the core once per pass and hands the virtual core to a waiter after 50 us of polling (TOTK_SPIN, TOTK_SPIN_HANDOFF_US)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 15:51:47 +03:00
Valiantsin DzerakhandClaude Opus 5.5 b245b07722 Let the installer build from the 1.2.1 or the 1.4.3 update
The check identifies the update by hash among layout.SUPPORTED and records it in totk-install.json; an install that
records none is 1.2.1. Extraction, lifting, compiling and preparing take the version from there: the patch table and
expected hashes per version, build_game.py --version (rt_game_version), make_romfs_patches.py and prepare_shaders.py
--version. Step keys of a 1.2.1 install stay as they were, so updating such an install does not extract again. Another
update file than the recorded one plans the extraction again (a copy of the same file is recognised by its hash), and
an identified version change re-plans every step after the check. The disk space estimate takes the larger RomFS.
Catalog strings name both versions and take the version as a parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 18:18:20 +03:00
Valiantsin DzerakhandClaude Opus 5.5 c8105294ed Explain peeled jump-table cases through the blocks above the dispatch region
The jump-table check now walks every way into the dispatch region up to four predecessor blocks and drops an oracle
index only where each way's branch condition, a pure function of the index register evaluated in Unicorn, rules it
out: cmp #k; b.ne with other instructions between, cbnz on the index, and range checks such as sub/cmp/b.hi or
and/cmp/b.ne. Branch targets inside a fall-through region count as entries. capstone lists the first operand of
cmp, cmn and tst as written; the slice reads it from the operands. 1.4.3 drops from 6 unexplained disagreements to 0,
1.2.1 stays at 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 17:42:45 +03:00
Valiantsin DzerakhandClaude Opus 5.5 914d9f5915 Unfinished 1.4.3 work: restore the jump-table check a session restart zeroed and explain peeled-case oracle targets, including taken bounds branches
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 17:27:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 776d547169 Load 1.4.3 modules: DT_RELR, symbol count from DT_GNU_HASH, stg as a no-op, version-aware boot anchors and loader probe values
The jump-table check now explains oracle targets for case indices peeled off by cmp #k; b.ne before the table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 17:27:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0ec06312d2 Recompute the end-to-end fixture's step keys for the checkout under test, because they fingerprint recomp/, tools/ and runtime/ and install-test was recorded by an older tree
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:05:49 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2d8a93f823 Re-render the window log from the kept events on a language switch, show language, step and input names instead of codes, reset the model on a new run and feed the selftest's ok screen a complete run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:27:39 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f1f8600294 Run the window's end-to-end test on hard links to install-test and skip it when the RomFS hash reads wrong three times on the machine with the faulty RAM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:24:08 +03:00
Valiantsin DzerakhandClaude Opus 5.5 826448e5e3 Add the installer window: a tkinter front end over the CLI with steps, progress, space, log, cancel, update mode and a self-closing selftest
The check step now emits a space event with the bytes the install needs and the free bytes. The window logic (event model, form, CLI subprocess, Ctrl+Break) is in installer/guilogic.py and tested without Tk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:13:42 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a56a0e6fda Extract the RomFS again when a kept image fails its full hash instead of trusting its index.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:50:46 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f2457495cc Add an end-to-end driver that runs the installer in dev mode with the game files of config.local.toml
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:26:47 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0431b62683 Add the installer core: the six setup steps, JSON progress events, totk-install.json resume and update, and explicit paths in the extract, build and shader tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:25:14 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2d714537e7 Run agent tasks in git worktrees
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 23:08:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 19c9b648d1 Add the recompiler, Windows runtime, tools and docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:27:54 +03:00