From d49ae962f24f2687d437fe8c40b98efe7af7e9d2 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Fri, 15 May 2026 23:38:33 +0200 Subject: [PATCH 1/9] Add battle-init smoke test and pre-push pytest hook Loads ff4-battle-ext.kss at the Battle_ext seed point, settles 120 frames, asserts the CPU never STPs, and pixel-matches the framebuffer against a PNG golden. Catches the regression that the bank-20 reloc iteration shipped: build + format hooks passed but the engine BRK-trapped during DrawText on first menu interaction. Wire pytest as a pre-push hook so the full kintsuki suite runs once before any push, catching similar codegen regressions before they reach the remote. --- .pre-commit-config.yaml | 9 ++++ tests/goldens/battle_init/battle_init.png | Bin 0 -> 10355 bytes tests/savestates/ff4-battle-ext.kss | Bin 0 -> 397021 bytes tests/test_battle_init.py | 55 ++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 tests/goldens/battle_init/battle_init.png create mode 100644 tests/savestates/ff4-battle-ext.kss create mode 100644 tests/test_battle_init.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d03e843..4a0e39b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,3 +19,12 @@ repos: files: \.(s|i)$ require_serial: true pass_filenames: true + - id: pytest + name: pytest (full suite, pre-push only) + description: Run kintsuki + golden tests before push to catch + patch regressions that build + format hooks can't see. + entry: pytest -q + language: system + pass_filenames: false + always_run: true + stages: [pre-push] diff --git a/tests/goldens/battle_init/battle_init.png b/tests/goldens/battle_init/battle_init.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb8374d2da7e5b86c1bbdebc56accd3d7e2539c GIT binary patch literal 10355 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 literal 0 HcmV?d00001 diff --git a/tests/savestates/ff4-battle-ext.kss b/tests/savestates/ff4-battle-ext.kss new file mode 100644 index 0000000000000000000000000000000000000000..28f8faea64cc9ae0be2948033013f6384b0bcaf3 GIT binary patch literal 397021 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 literal 0 HcmV?d00001 diff --git a/tests/test_battle_init.py b/tests/test_battle_init.py new file mode 100644 index 0000000..0a3d32f --- /dev/null +++ b/tests/test_battle_init.py @@ -0,0 +1,55 @@ +"""Battle-init smoke test. + +Regression guard for the bank-20 relocation work. The +`.alloc bank20_modules` wrap (overflow Q#13 / Q#14 era) shifted bank-20 +symbol addresses in a way that caused the engine to BRK / STP during +battle redraw on the first menu interaction. The build still succeeded +and the IPS coverage looked normal, so a pure build-side check would +have missed it. This test boots the patched ROM into a battle-running +savestate, lets a few frames settle, asserts the CPU never halted, and +records a PNG golden of the framebuffer. + +Recorded once via UPDATE_GOLDENS=1; replays as a pixel-match thereafter. +""" +from __future__ import annotations + +from pathlib import Path + +import pytest + +from _ff4kintsuki import ( + assert_screenshot_matches_golden, + kss_path, + load_emu_from_kss, +) + +GOLDENS = Path(__file__).parent / "goldens" / "battle_init" +KSS = kss_path("ff4-battle-ext.kss") + + +@pytest.fixture +def battle_emu(): + emu = load_emu_from_kss(KSS, settle_frames=120) + yield emu + emu.close() + + +def test_battle_init_no_stp(battle_emu): + """If the CPU executed STP during the settle frames, the patch is + broken: the BRK trap (or any rogue opcode) halted the emulator. + Catches the bank20_modules wrap regression that fired + `brk_handler -> STP` from $02:A455 during DrawText.""" + s = battle_emu.get_state() + assert s.stp == 0, ( + f"CPU halted via STP during battle init: PC=${s.pc:04X} " + f"PB=${s.b:02X} A=${s.a:04X}. The bank-20 reloc patch likely " + "corrupted bank-02 code; check `git log -- ff4.s` for recent " + "allocator or *= changes." + ) + + +def test_battle_init_screen_golden(battle_emu): + """Pixel-match the framebuffer 120 frames into the battle state. + Sensitive to any rendering regression that survives the no-STP + check (garbled tiles, wrong palette, broken text).""" + assert_screenshot_matches_golden(battle_emu, GOLDENS / "battle_init.png") From a923c26947357ee82b5a4eb4cc8cef87d141acb0 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Fri, 15 May 2026 23:42:18 +0200 Subject: [PATCH 2/9] Settle 600 frames so battle-init golden captures rendered state 120 frames left the slice-2 redraw gates clean: names and the cmd list intentionally do not draw on the first ATB tick. Bump to 600 frames so ATB fills the first character's command list and the golden actually exercises the rendering path the bank-20 reloc regression broke. --- tests/goldens/battle_init/battle_init.png | Bin 10355 -> 11227 bytes tests/test_battle_init.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/goldens/battle_init/battle_init.png b/tests/goldens/battle_init/battle_init.png index ffb8374d2da7e5b86c1bbdebc56accd3d7e2539c..6d0e5fe8068c6a3735889e19e31e45d3cbc4032e 100644 GIT binary patch literal 11227 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 JH=H<0{|9~@0>=OV diff --git a/tests/test_battle_init.py b/tests/test_battle_init.py index 0a3d32f..05f9897 100644 --- a/tests/test_battle_init.py +++ b/tests/test_battle_init.py @@ -29,7 +29,7 @@ @pytest.fixture def battle_emu(): - emu = load_emu_from_kss(KSS, settle_frames=120) + emu = load_emu_from_kss(KSS, settle_frames=600) yield emu emu.close() @@ -49,7 +49,7 @@ def test_battle_init_no_stp(battle_emu): def test_battle_init_screen_golden(battle_emu): - """Pixel-match the framebuffer 120 frames into the battle state. + """Pixel-match the framebuffer 600 frames into the battle state. Sensitive to any rendering regression that survives the no-STP check (garbled tiles, wrong palette, broken text).""" assert_screenshot_matches_golden(battle_emu, GOLDENS / "battle_init.png") From 714d24fedf0667b16627245865db39b4c893d258 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Fri, 15 May 2026 23:44:38 +0200 Subject: [PATCH 3/9] Force redraw-gate dirty bits before settle so names and monster render Slice-2 redraw gates stayed clean through the 600-frame settle, so the golden captured battle with empty name + monster headers and only the cmd list visible. Poke battle_menu_dirty ($7E:EF9A) and battle_monster_dirty ($7E:EF9B) to $FF plus the slice-2 region_dirty_bits queue at $70:3C01 before running frames, so DrawCharNames + DrawMonsterNames fire on the first frame. Golden now shows monster sprite + label, char names, cmd list and HP/MP boxes. --- tests/goldens/battle_init/battle_init.png | Bin 11227 -> 11505 bytes tests/test_battle_init.py | 11 ++++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/goldens/battle_init/battle_init.png b/tests/goldens/battle_init/battle_init.png index 6d0e5fe8068c6a3735889e19e31e45d3cbc4032e..c8f095571aadd101bdb677c2c4117575d3d6ddf0 100644 GIT binary patch delta 2444 zcmcgsX;9O768(pSKp>X^F$95JAgD-?a0voA2p|v;5rN5KIK&|0BCt+Gog_d)kbsHG zDM28P!U(Pij;QDc7K1wq$qVB&7oZq?S-R_&MledyQK{p;6V@5B3L z&tkNkWW2dGkV%W+$0lI)6+1}^uBn2HYRddX6pZnDizEOUvaluv_ba~+qhI*$e$TbkTk)* zvbgh#fGbM8Y7Mi9fp@D2MBNXO!?s9GM2w}VJrr7l@BEwieW)Sk$5l{E8#luDd_8za zoDnj7uh77X@=a#i&%~fLXUNinh?SlsM{sKbl$@W5a>zcLyL*jXlwM5|CMz{>OeW<> zd$z#~n-eE~%P~Nel$L^BD$bn)3--*n2Ll)BKF|wRbHk}cjJE^m`(8YS)MG$cQY|vl zH04x+jk&*T1F#v$MLXd z*Vdgnrtv5oPi3diD5dL9;+-50Wk+QBVxnByNwBi|VIur)7WyWY&i=$Z$lom~zo7`R zb(-BpSWB2S8>ldfO=&mxbwR%$ZX8Y%;~EPb_&eDt1=2ybdfd|MCKxQ{77_0~R&yZc zbFKVEqL)ADk?(7PJnz?brCZn>1V!=+{Ot3pfw&U9VBKR%2B!k)HaVP+6dA?$hAm*( zQ9SVmG7zMuA}ZD2KZcl6W}~8`PkdOQ`T7E<3xq2M>7tOk2|Yywgb026zS+$V5YF%F zVfyP5VCdS%c3b`&HTN2(ZJ9QNlKXZa+NE?IvpPVDS4*4pXz z9$y5_f>oVeBu8_HKuH$WX2!uo}RC*mv zUvAZx?4-P82>+pmD>fuUCk4P@>i#1)%smB7VsSjfwIfNm{$P2{?oljHZG>b5;p!O?|D&IJf)q%TLh@umaTg_oCnak?%e8Y z)VD9~-VP%p7gw<+C(2?L;5%ycJ-zG-bVWImZ85~%c%T*|Obr8Rj< zRP+A)+5DL7p>7{cfZyIT&%fKsI#d55f?t)_3bLB)eOfjIKFKx0$m|E&AZ`Yi@4)La zLgbv>9wjgOkfzzhAwyw3v%^dJC$-ad?h}~nwY**CluiW+j#}q%2+!e=$;g#mE@MOk z5@|Gx&Y8cYoMQ?~92eBgelq%S;%v=6fK@wdC11jj6S#<@{6im4rNWG-lxYHOc&O@Z z@WBLB+rnAVdm!Wf=?NCzOCyB0w2CrDIMp1#mDmegwhfQk9W@8Xn-+$nA24qQd9Cul2O=Lo==)>1YtFs9b~Omr2yF zvaE0?2D%n{x-)QNO1=#Kg-z@hXKsQv*?#-HLF}?@r}IQl;$ZtTE1g;yOOmi>IvlKgKJM$^<~GI%Gc@ztF&j>c3T9m>!0C7T{i4ls@TihyYlqX z>gvR)FZ4TsT&FzA4Gq(|u*!ixQz2_l5sfa z1B?C0$%}Y%+K#+7<_)RU$|G3lE#?(-EK2}#p#$Nnjsgl_^X#kB)a=%v_mGU~Oy~tK z+>a^m@ink~KkkRxu1%cv(FXu$(~F+kNx)w zO2OB4|BW-u0m5n?S$k`1N`Z z-+1mzN*bm1CZ~E|Uw^*bzVN5Inx`v@l0T+(3D%iweXo;NFNK^dDK7T&E2VikpV;g=*MPWp>wl;2X}KB=l}o! delta 2169 zcmbVLYgm%m7Urg+f}jz6TuM+2vka6^OJxjGIpnRJ?4p%}S`K!Z=w>=v+`OScFiobW zjfthDmYPl0(GH5EIAKAQl?P{hwA9MVbf(LUCl7Ugo%5Vuvw!S&J!|dv-OqaWUT+fr zxkc^iyu4;zL|8&ravET#iTBj-aT-3R@w3pZYxDXv=a$coUnH&8{u&lL^vTanP?@>Q-T-Kx2+h^TOM|%e2 zbd6wzm>VuOV8s(2ZIvv=izPgRn)Ny%KHjgQnHvrfz0BK`2|SFh-9_i)y936+3el(Z zVpzMsvH32~>tUSQj2!KydB^hAjw_3n>CR<0E-zE(Tu0R_XHtHx2fT=YuM_q1+E)zP zgva(#!*QDbX!DTsIylGeYW_Or^^MEf>$Wb061^RgP%$sSs$;NuF|X!{*u=hI}AS zH@Jv>1Kv~@se%PgQ?-i-jATSB?JS~If_jqjt#AUJ5YnYbt{2Yzt!h(`yKw$MOqjm{ zmQc=8|A2?riEE%35Xeo}MV=4XbC)4^5b2ogfoEM>H|cQJDUausd* z0guPGA1h%oQue)0X%bSU(^k9wNP*StBPsFl8m;$KwE?+kxqirmsIs z`Qn=tFc$L>OAQQx&bl?DxfY6@F-W&})(xfVf~0qX6_>c-d{Y6W<*{SgX>r;hI1sPy zvgfN{_Jh#?q*dZEPrJTKbwO*!0#+JlY6D{DM~AgA(F^a2%=6SBrywhHOQb0%q0qvA zB`B@kfyADv5;rUmXFIlXp|1_(MIO$rZ|-11IenbY9iSoYg@U*3R|6m>1zyBwAI1ey znv3WA$|m*qrF5pI#P_?Y{90&M*@DA#Won_^>ySii=fY>2GJe9iz0z&?bN$Z|zF}XF zxjTv|lBdBPMrj^urV_&h#Zqh@-hZo|V=pc}S$anHAoKA@j!Bpb+ir*2@C2#XN0yM01cIYnHlHxi7Vf>R`;aTU(<5ZDo53KFl|qYt$l=_H zRx64Fo|vuhqo|9cU@H$nUb5 zhmaRmUksB5>?OwEE$7@0QX32Qx?X&q;kti?-rtXN5Z9sBD;&YEJn61R$cHswHY{zm z*dJW#B|r{#mRr0Zv;0sSAx7GCjNLnrY$7}r_i@E4g-iow-;K9)t^f zT9XFdlMEXwx}E!pbgN+Z%e=&SYTqh$H}%|!3&57)d`b^Cz>s}#XF5IW=iV4m77WpV zdn3jEU0A-}_dwEqr+D;xJLfjZz)0DLxdE+5-s_)SlX5X4Z zQD(O#PnUE~Ik@HfJV@=wLPE;4u5U>kH(5$nH4+lBzZl6)RYhnh?>ERM)@bKSw~fS( z&O+i-t%xZ1p@|#jx_wl2&HAT+zmcZL&q!0>UwN!YMHL~3rCH!RlB3(q`ke z&o;_!HhyxE1fV5d1eo@kMR19NmY9b!K(wMjCwK`~*xN=DDAWnk_Ji3cY$+RlF8w!( zbOI#SMPj~X5%>_%&`bG{mxEIu;`^0nxM?{cq96*X7_`0G5fD+2hiM;YfPPAwRwgMH zuB9>GujRMd!c(>|DMWceVjJ(KDz3#Qi5kNK`=*pjU)xeP{9O89L_@o2OwrI$QtXn? zeesFt+fXOyKg??PR`kfx_dCLyu2Lzo!T@|S31UG zoo^upBv{wnn^|`Gy@w~IJ`m@(Z>X)YafQ!K)M)uL%ek{Pnh#)9Fy~=SIlIkv@E|Td zS3`g)z85)AYE9=$WhSfMVBl?>%{cvyIN#Yc{mfE_iGO#Zjbe9#5yig4JGDW(gOwiK z{w=9yp!Qkw%_D8)tGxW_>{|f0OMv`j`Cr?1{YBpYr*Xm|kVTZP>O+xDcOka5E;26S I@>;(1-x&n00ssI2 diff --git a/tests/test_battle_init.py b/tests/test_battle_init.py index 05f9897..a8765e4 100644 --- a/tests/test_battle_init.py +++ b/tests/test_battle_init.py @@ -29,7 +29,16 @@ @pytest.fixture def battle_emu(): - emu = load_emu_from_kss(KSS, settle_frames=600) + emu = load_emu_from_kss(KSS, settle_frames=0) + # Force every redraw gate dirty before settling so the smoke test + # exercises DrawCharNames / DrawMonsterNames / DrawCmdWindow on the + # first frame. Without this the slice-2 gates stay clean (the gate + # state only re-arms on writer-side state changes like ATB rotation + # or HP delta) and the golden captures an empty header strip. + emu.write(0x7EEF9A, 0xFF) # battle_menu_dirty: all chars + cmd + status + emu.write(0x7EEF9B, 0xFF) # battle_monster_dirty: all monster slots + emu.write(0x703C01, 0xFF) # region_dirty_bits: slice-2 queue + emu.run_frames(600) yield emu emu.close() From 1996962cffc53321081499c9fba061fa94176a66 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 10:28:24 +0200 Subject: [PATCH 4/9] Skip the 8-row blit loop when battle VWF renders a space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Space ($FF) glyph bytes are all zero so the row loop only OR-stores zeros into the tile buffer — visually a no-op, but it still pays the 8 `lda assets_menu_font_dat, x` + `inx` round-trip plus the shift / store dance when bits_left_on_tile is unaligned. Bump X past the glyph rows up front and jump straight to brk_bits_left so the width byte still drives the tilemap advance. --- src/battle/message.s | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/battle/message.s b/src/battle/message.s index 93a240a..5ba3957 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -24,6 +24,8 @@ init: Base tile ID for ring buffer area - byte A: the base tile id """ + + ; tile_ring_base_tile should be set to your VWF tile area start ; With 0x128 dynamic + 0x128 immortal = 0x250 (592) tiles total ; But tile IDs are 1 byte (0-255), so max usable is 0xFF @@ -38,6 +40,8 @@ allocate_tiles: Allocate next 8-tile slot Returns: A = starting tile_id (byte), X = allocation ID (word) """ + + ; Calculate tile_id: base_tile + (head * TILES_PER_ENTRY) lda.w tile_ring_head ; Multiply by 8 (shift left 3 times) @@ -55,6 +59,8 @@ commit_allocation: Commit the allocation (call after rendering to tiles) X = allocation ID """ + + { ; Advance head pointer lda.w tile_ring_head @@ -83,6 +89,8 @@ Get tile_id of a specific allocation by ID A = allocation ID (word) Returns: A = starting tile_id (byte), Carry = 0 if found, 1 if expired """ + + { ; Check if ID is still valid (within current range) sec @@ -266,6 +274,8 @@ clear_buffer: Wipe the 16×region_size 4bpp tile buffer for the currently-allocated VWF tile id (sets each plane row to $FF/$00). """ + + pha phx phy @@ -336,6 +346,8 @@ display_char: Render `A` (char) at tilemap offset `Y` into the message VWF buffer ; preserves A/X/Y, returns Y = `tilemap_offset`. """ + + pha phx phy @@ -358,6 +370,23 @@ _display_char: jsr.w _adjust_bits_left_for_kerning pla } + +; Space ($FF) renders blank ; the 8-row loop only OR-stores zeros (no +; visible effect) and reads 8 glyph bytes plus 8 inx ops we can skip. +; Bump X past the glyph rows so `brk_bits_left` reads the width byte +; from the right offset, then jump straight to the width-update tail. + lda.b current_char + cmp #0xff + bne _not_space + rep #0x20 + txa + clc + adc.w #0x0008 + tax + sep #0x20 + jmp.w brk_bits_left +_not_space: + rep #0x20 lda.w #0x0008 sta.b counter @@ -693,6 +722,8 @@ put char write to the tilemap if needed maintain counters """ + + cmp #0x42 bcc put_fixed_char_dakuten put_fixed_char_no_dakuten: @@ -714,6 +745,8 @@ init: inits the renderer for the messages window flips the flag for enabling the messages renderer. """ + + jsr.l battle_flags.set_vwf_render jsr.w battle_render.init rtl @@ -738,6 +771,8 @@ set. Writes `$FF` to `render_skipped` so the gated trampoline can short-circuit DrawText and the matching `deinit_gated` skips the DMA signal. """ + + jsr.l battle_flags.set_vwf_render jsr.w battle_render.init_monsters_gated rtl @@ -756,6 +791,8 @@ deinit: the renderer disables messages renderer falling back to fixed mode. """ + + jsr.l battle_flags.clear_vwf_render ; vram transfer was moved to a trampoline in the battle nmi. lda.l battle_render.pending_transfer_mask @@ -768,6 +805,8 @@ Companion to `init_*_gated`: always flips the flag back, only signals DMA (sets bit 0 of pending_transfer_mask) if the matching init actually rendered. Reads `render_skipped` to decide. """ + + jsr.l battle_flags.clear_vwf_render lda.l battle_render.render_skipped bne _deinit_gated_done @@ -796,6 +835,8 @@ INIDISP write at `$02:837F` after the NMI DMA chain. On idle frames (nothing queued) forced-blank is NOT set ; vblank stays normal length, no visible black strip. """ + + pha phx phy @@ -917,6 +958,8 @@ new_line_escape_code_handler: Handler for the ` ` text-stream escape: allocate a fresh tile via `render_allocator.increment`, reset bits_left_on_tile to 8, and advance the tilemap offset by one row (16 tiles). """ + + ; we might have something of interest in Y we might know where we are in the previous iteration ? pha ;jsr.w battle_render.tilemap_write From 56b8e387addf3a05911a4b84498b84b979255a75 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 11:25:55 +0200 Subject: [PATCH 5/9] Add VWF profiler scoped around display_char for A/B comparisons Loads ff4-battle-ext.kss, pokes every redraw-gate dirty bit so the char names, monster names and command list re-render on every profiled frame, then runs profile_start over the 4 KB neighbourhood around battle_render.display_char and prints per-function call counts plus inclusive / exclusive cycles. Sorts by exclusive so the hot inner loops surface first. Use as the baseline before / after any change to the 8x8 VWF blit or the kerning binary search: python3 tests/_profile/profile_battle_vwf.py > /tmp/vwf.before # apply change, rebuild python3 tests/_profile/profile_battle_vwf.py > /tmp/vwf.after diff /tmp/vwf.before /tmp/vwf.after Current numbers on master: _display_char 22 calls, 140k excl cycles over 60 frames; _get_kerning_adjustment_binary_search 22 calls, 84k cycles ; _adjust_bits_left_for_kerning 103k inclusive. --- tests/_profile/profile_battle_vwf.py | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/_profile/profile_battle_vwf.py diff --git a/tests/_profile/profile_battle_vwf.py b/tests/_profile/profile_battle_vwf.py new file mode 100644 index 0000000..b403fc4 --- /dev/null +++ b/tests/_profile/profile_battle_vwf.py @@ -0,0 +1,92 @@ +"""Profile the battle VWF blit path with all redraw gates forced dirty. + +Loads ff4-battle-ext.kss at the Battle_ext seed point, pokes every +redraw-gate dirty bit so DrawCharNames + DrawMonsterNames + DrawCmd +fire on every profiled frame, then runs `profile_start` scoped to the +display_char neighbourhood in bank $20 and reports per-function call +counts + inclusive / exclusive cycles. + +Use as the A/B baseline before/after VWF optimisations: + + python3 tests/_profile/profile_battle_vwf.py > /tmp/vwf.before + # ... apply change, rebuild ... + python3 tests/_profile/profile_battle_vwf.py > /tmp/vwf.after + diff /tmp/vwf.before /tmp/vwf.after +""" +import sys + +sys.path.insert(0, "tests") +from _ff4kintsuki import kss_path, load_emu_from_kss + +PROFILE_FRAMES = 60 +WARMUP_FRAMES = 30 + +# Pull display_char neighbourhood from build/ff4.sym so the bench +# follows allocator address shifts. +SYM = {} +for line in open("build/ff4.sym"): + parts = line.strip().split(" ", 1) + if len(parts) != 2: + continue + bank, _, off = parts[0].partition(":") + try: + SYM[parts[1]] = (int(bank, 16) << 16) | int(off, 16) + except ValueError: + pass + + +def label(pc: int) -> str: + near = max((p for p in SYM.values() if p <= pc), default=None) + if near is None: + return f"0x{pc:06x}" + name = next(n for n, p in SYM.items() if p == near) + return name if pc == near else f"{name}+0x{pc - near:x}" + + +display_char = SYM["battle_render.display_char"] + +# Scope: 4 KB around display_char captures the whole blit + kerning +# tail without dragging in unrelated bank-20 callers. +lo = display_char & ~0xFFF +hi = lo + 0x1000 + + +def force_redraw(emu): + emu.write(0x7EEF9A, 0xFF) # battle_menu_dirty: chars + cmd + status + emu.write(0x7EEF9B, 0xFF) # battle_monster_dirty: all monster slots + emu.write(0x703C01, 0xFF) # region_dirty_bits: slice-2 queue + + +def run(): + emu = load_emu_from_kss(kss_path("ff4-battle-ext.kss"), settle_frames=0) + force_redraw(emu) + emu.run_frames(WARMUP_FRAMES) + force_redraw(emu) + emu.profile_start(lo=lo, hi=hi) + for _ in range(PROFILE_FRAMES): + emu.run_frames(1) + force_redraw(emu) + stats = emu.profile_stop() + emu.close() + return stats + + +def main(): + stats = run() + incl_total = sum(s.incl_cycles for s in stats) + excl_total = sum(s.excl_cycles for s in stats) + print(f"Scope: 0x{lo:06x}..0x{hi:06x}") + print(f"Frames profiled: {PROFILE_FRAMES} (warmup: {WARMUP_FRAMES})") + print(f"Functions captured: {len(stats)}") + print(f"Total inclusive cycles: {incl_total:,}") + print(f"Total exclusive cycles: {excl_total:,}") + print() + print(f"{'function':<48} {'calls':>8} {'incl':>12} {'excl':>12} {'avg/call':>10}") + print("-" * 96) + for s in sorted(stats, key=lambda x: -x.excl_cycles)[:20]: + avg = s.excl_cycles // max(1, s.calls) + print(f"{label(s.pc):<48} {s.calls:>8} {s.incl_cycles:>12} {s.excl_cycles:>12} {avg:>10}") + + +if __name__ == "__main__": + main() From 6811d2df2cda7df4d8db896340dec285d9fbc4c8 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 11:27:51 +0200 Subject: [PATCH 6/9] Skip kerning binary search when either side of the pair is a space prev_char or current_char of \$FF (space) has no kerning entries in any font's pair table, so the binary search always reports "not found" after walking the full table. Early-out at the top of _adjust_bits_left_for_kerning and fall through to _finalize so prev_char still advances for the next call. Profile delta on the battle VWF bench (60 frames, all redraw gates forced dirty): binary search calls: 22 -> 15 (-32%) binary search cycles: 84792 -> 57670 (-32%) _adjust_bits_left incl: 103824 -> 74088 (-29%) total incl (60f): 3107570 -> 2931590 (-5.7%) --- src/battle/message.s | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/battle/message.s b/src/battle/message.s index 5ba3957..d88c109 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -519,6 +519,16 @@ coupe: .if ENABLE_KERNING_MENU { _adjust_bits_left_for_kerning: { +; Space ($FF) is never a kerning pair partner ; skip the binary search +; entirely when either side of the pair is a space. Still falls through +; to _finalize so prev_char stays in sync for the next call. + lda.b prev_char + cmp #0xff + beq _finalize + lda.b current_char + cmp #0xff + beq _finalize + lda.b bits_left_on_tile sta.b temp From 40aabe16481abaf7c1f269bcf7a0d873cc547523 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 11:42:24 +0200 Subject: [PATCH 7/9] Hoist VWF shift dispatch into 8 specialized per-shift inner loops Tier-2 optimisation. The original char_line_loop ran the cmp #8 + jmp-table dispatch + asl ladder per row even though bits_left_on_tile is invariant across the 8 rows of a single glyph. Hoist the classification to glyph entry, dispatch once into one of 8 loops (aligned + shift_0..shift_7) whose asl chain is baked into the body via a .for macro. Aligned drops the redundant ora/sta on the high bitplane (always a noop) for an extra ~80 cy/glyph. X holds the font pointer at entry and the shift dispatch clobbers it for the indirect jump, so the font pointer is stashed in temp first and each shift loop restores it via ldx.b temp on entry. Aligned bypasses save / restore since it never touches X. Profile delta on the battle VWF bench (60 frames, all redraw gates forced dirty): _display_char excl: 139954 -> 97588 (-30%) _display_char avg: 6361 -> 4435 (-30%) total inclusive: 2931590 -> 2416816 (-17.6%) total exclusive: 819092 -> 773366 (-5.6%) Cumulative vs master (space-skip + kerning early-out + tier 2): total inclusive: 3107570 -> 2416816 (-22.2%) _display_char avg: 6365 -> 4435 (-30.3%) ROM cost: +375 bytes in bank-20 reloc (build/ff4.ips 262313 -> 262686). Bank-20 still well under capacity. --- src/battle/message.s | 175 +++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 64 deletions(-) diff --git a/src/battle/message.s b/src/battle/message.s index d88c109..154a9cb 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -387,80 +387,63 @@ _display_char: jmp.w brk_bits_left _not_space: +; Tier-2 hoist: classify bits_left_on_tile once per glyph, dispatch to +; one of 8 specialized 8-iteration loops (aligned + shift_0..shift_7). +; Each loop bakes the asl count into its body so the per-row +; cmp/jmp-table/mul-ladder dance disappears. Loops jump to brk_bits_left +; on completion. +; +; X holds the font pointer at entry. The shift dispatch clobbers X for +; the indirect jump, so the font pointer is stashed in `temp` first and +; each shift loop restores X from there on entry. The aligned path +; keeps X untouched so it bypasses the save / restore. rep #0x20 lda.w #0x0008 sta.b counter sep #0x20 -char_line_loop: - rep #0x20 - lda.w #0x0000 - sep #0x20 - lda.b bits_left_on_tile - cmp #0x08 - bne _shift - -_read_8x8_char: - lda.l assets_menu_font_dat, x - xba - lda.b #0x00 - xba - inx - xba - bra _store + beq _aligned_loop -_shift: -; PPU multiplication is being used by the NMI which wrecks char lines once in a while phx - lda.l assets_menu_font_dat, x - xba - lda #0x00 - xba + rep #0x20 + pla + sta.b temp + sep #0x20 -; make jump_table_pointer - pha lda.b bits_left_on_tile asl - tax + pha + lda #0x00 + xba pla - + tax + jmp.w (_shift_dispatch, x) + +_shift_dispatch: + .dw _shift_loop_0 + .dw _shift_loop_1 + .dw _shift_loop_2 + .dw _shift_loop_3 + .dw _shift_loop_4 + .dw _shift_loop_5 + .dw _shift_loop_6 + .dw _shift_loop_7 + + .macro vwf_row_body(n) { rep #0x20 - jmp.w (_mul_table, x) -_mul_table: - .dw _mul_0 - .dw _mul_1 - .dw _mul_2 - .dw _mul_3 - .dw _mul_4 - .dw _mul_5 - .dw _mul_6 - .dw _mul_7 - .dw _mul_8 - -_mul_8: -_mul_7: - asl ; 1 -_mul_6: - asl ; 2 -_mul_5: - asl ; 3 -_mul_4: - asl ; 4 -_mul_3: - asl ; 5 -_mul_2: - asl ; 6 -_mul_1: - asl ; 7 -_mul_0: + lda.w #0x0000 sep #0x20 - plx + lda.l assets_menu_font_dat, x inx - -_store: - + .if n > 0 { + rep #0x20 + .for k := 0, n { + asl + } + sep #0x20 + } xba phx tyx @@ -473,15 +456,79 @@ _store: plx iny iny + dec.b counter + } -_next_line: +_aligned_loop: + lda.l assets_menu_font_dat, x + inx + phx + tyx + ora.l buffer_ptr + 1, x + sta.l buffer_ptr + 1, x + txy + plx + iny + iny dec.b counter - bne char_line_loop + bne _aligned_loop + jmp.w brk_bits_left - rep #0x20 - stz.b temp - lda.w #0x0000 - sep #0x20 +_shift_loop_0: + ldx.b temp +_shift_loop_0_body: + vwf_row_body(0) + bne _shift_loop_0_body + jmp.w brk_bits_left + +_shift_loop_1: + ldx.b temp +_shift_loop_1_body: + vwf_row_body(1) + bne _shift_loop_1_body + jmp.w brk_bits_left + +_shift_loop_2: + ldx.b temp +_shift_loop_2_body: + vwf_row_body(2) + bne _shift_loop_2_body + jmp.w brk_bits_left + +_shift_loop_3: + ldx.b temp +_shift_loop_3_body: + vwf_row_body(3) + bne _shift_loop_3_body + jmp.w brk_bits_left + +_shift_loop_4: + ldx.b temp +_shift_loop_4_body: + vwf_row_body(4) + bne _shift_loop_4_body + jmp.w brk_bits_left + +_shift_loop_5: + ldx.b temp +_shift_loop_5_body: + vwf_row_body(5) + bne _shift_loop_5_body + jmp.w brk_bits_left + +_shift_loop_6: + ldx.b temp +_shift_loop_6_body: + vwf_row_body(6) + bne _shift_loop_6_body + jmp.w brk_bits_left + +_shift_loop_7: + ldx.b temp +_shift_loop_7_body: + vwf_row_body(7) + bne _shift_loop_7_body + jmp.w brk_bits_left brk_bits_left: From 40f38c43af956dadd026ae7d7fee83b86a345bfa Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 11:52:04 +0200 Subject: [PATCH 8/9] Skip binary search at entry when either char is space Push the space-pair early-out down into each of the three kerning binary searches (battle_render, dialog VWF, small_vwf). The previous patch only short-circuited at _adjust_bits_left_for_kerning, so external callers like battle_msg_kerning_binary_ext and the dialog + small_vwf entry points still walked the full table for space pairs. Now every binary search bails before touching the table when prev_char or current_char is \$FF. Costs ~22 cy per non-space call on the path that already had the adjust-level early-out (battle bench shows +14k inclusive cycles in 60 frames, well within noise) but recovers the win uniformly across all three VWF surfaces and all external callers. --- src/battle/message.s | 20 ++++++++++++++++++++ src/kerning.s | 12 ++++++++++++ src/small_vwf/render.s | 19 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/battle/message.s b/src/battle/message.s index 154a9cb..4657c2e 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -615,6 +615,18 @@ _finalize: _get_kerning_adjustment_binary_search: { +; Space ($FF) never appears in any font's kerning pair table; bail out +; before the bank push so external callers (battle_msg_kerning_binary_ext +; and Python tooling) skip the search too. Caller is in 16-bit M. + sep #0x20 + lda.b prev_char + cmp #0xff + beq _space_skip + lda.b current_char + cmp #0xff + beq _space_skip + rep #0x20 + phb pea.w font_table >> 16 plb @@ -713,6 +725,14 @@ not_found: plb rts +_space_skip: +; Space-pair early-out: 8-bit M from the entry check, no bank push or +; search bounds were pushed yet. Just signal "not found" and return. + rep #0x20 + lda.w #0x0000 + sec + rts + found_pair: ; This label kept for compatibility but shouldn't be reached ; in binary search version diff --git a/src/kerning.s b/src/kerning.s index 9c9e536..64f2646 100644 --- a/src/kerning.s +++ b/src/kerning.s @@ -25,6 +25,18 @@ A=0+sec on miss. Trashes A/Y/flags, preserves X. _dialog_get_kerning_adjustment_binary_search: { +; Space ($FF) never appears in any font's kerning pair table; bail +; before reading the count when either side of the pair is a space. +; Caller is in 16-bit M. + lda.b CURRENT_C + and.w #0x00ff + cmp.w #0x00ff + beq _return_zero + lda.b CURRENT_C + and.w #0xff00 + cmp.w #0xff00 + beq _return_zero + ldy.w #0x1100 lda.b [font_addr], y ; NumKerningPairs (16-bit) beq _return_zero diff --git a/src/small_vwf/render.s b/src/small_vwf/render.s index 1e6d0a7..73448f8 100644 --- a/src/small_vwf/render.s +++ b/src/small_vwf/render.s @@ -455,6 +455,17 @@ _overflow: _get_kerning_adjustment_binary_search: { +; Space ($FF) never appears in any font's kerning pair table; bail +; before the bank push so callers skip the binary search entirely. + sep #0x20 + lda.b prev_char + cmp #0xff + beq _space_skip + lda.b current_char + cmp #0xff + beq _space_skip + rep #0x20 + phb pea.w font_table >> 16 plb @@ -523,6 +534,12 @@ not_found: plb rts +_space_skip: + rep #0x20 + lda.w #0x0000 + sec + rts + _found: iny iny @@ -570,6 +587,8 @@ tilemap_write: inc.b tilemap_offset inc.b tilemap_offset} ) + + pla rts } From bfad9e3ef19b7d78691a15b482924390160beda2 Mon Sep 17 00:00:00 2001 From: Emmanuel Peralta Date: Sat, 16 May 2026 12:37:57 +0200 Subject: [PATCH 9/9] Drop redundant space early-out from _adjust_bits_left_for_kerning The binary search itself now bails on space pairs, so the adjust-level check is duplicate work. Keep the early-out at the single load-bearing site (the binary search entry) and let the adjust wrapper fall through to its normal jsr.w get_kerning_adjustment which returns carry-set immediately for space pairs. --- src/battle/message.s | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/battle/message.s b/src/battle/message.s index 4657c2e..3eb6003 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -566,16 +566,6 @@ coupe: .if ENABLE_KERNING_MENU { _adjust_bits_left_for_kerning: { -; Space ($FF) is never a kerning pair partner ; skip the binary search -; entirely when either side of the pair is a space. Still falls through -; to _finalize so prev_char stays in sync for the next call. - lda.b prev_char - cmp #0xff - beq _finalize - lda.b current_char - cmp #0xff - beq _finalize - lda.b bits_left_on_tile sta.b temp