re: three ISL built-in names were wrong, including the most-used one

All re-read twice — the handler, and the thing it calls — because each had
been named from its shape rather than its effect.

* id 11 `yield` -> `end_coroutine`. 0x82272624 is li r11,1 ; li r3,3 ;
  stw r11,164(r31), and the dispatcher's r3==3 arm erases the thread from
  the active list and returns it to the free list. It destroys the thread.
  2945 sites game-wide, 372 in Stage 02 — the most-used built-in there was.
* id 5 `await_label` -> `kill_coroutine(label)`. sub_82273B08 kills the
  thread parked at the target pc, or itself if the target is its own pc.
  It waits for nothing.
* id 100 `push_trigger` -> `reset_phase_threads`. It clears the trigger
  container and then frees every thread whose pc differs from the caller's
  — the opposite of pushing a trigger. Corroborated by usage: its 12 Stage
  02 sites all sit in the phase terminator, next to timer_stop,
  clear_flag(-1) and MARK_LAST_PHASE.

One name recovered from the game's own text: opcode 992 prints
"RequestScriptMessage %s" at 0x820A5700, so id 64 is request_script_message
(2683 sites).

Return codes documented properly: 1 = restart the coroutine from its entry
(previously not recorded at all), 3 = terminate. And the blocking set was
wrong in two places — it is 102, 120, 137, 142, 143. Id 97 does NOT block;
its handler ends `b 0x822724F8`, so it always returns 0.

Unit-operand resolution settled from DATA over all 28 stages rather than by
reading 147 handlers: a slot qualifies only if every value is a valid
symtab-2 index, it takes >=15 distinct values, AND its maximum reaches most
of the table — that last clause is what discriminates, since every small
integer is trivially "in range". 31 built-ins at slot 4, 8 at slot 12, one
at slot 20. It also refutes set_flag's slot 0, whose maximum overruns the
table, and the resolver now declines rather than inventing a name.

New and unexplained: symtab-2 holds two types, 2 and 8, and built-ins 95 and
128 take type 8 at slot 12 in 100% of their sites.

A downstream inference is withdrawn with it: the note reading the live
trigger counter attributed it to "the script arming watches as it goes" via
built-in 100. The measurement stands; the attribution does not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-25 22:09:05 +00:00
parent 723fc9b890
commit 1ba5d0a4a3
5 changed files with 261 additions and 56 deletions

View File

@@ -1,5 +1,7 @@
# Stage02.ssb — ISL disassembly artefacts
Generated by `tools/re-capture/isl_report.py calls`.
2846 call sites, 73 distinct built-ins
builtin 11 372 site(s)
builtin 69 255 site(s)
@@ -81,40 +83,47 @@
39 MARK_LAST_PHASE 8: 0x4dfc 0x52c8 0x60fc 0x19258 0x19724 0x2b584 0x2ba50 0x2c054
40 mark_not_last 4: 0x5a10 0x1a270 0x2c578 0x2d06c
## condition vocabulary actually used by Stage 02
11 yield 372
69 unit_state 255
1 start_coroutine 216
30 objective_marker 179
20 hp_pct_test 167
18 dist_lt 92
5 await_label 83
70 unit_alive 71
56 unit_relation 52
4 wait_s 34
26 damage_unit 33
3 move_order 20
124 timer_stop 15
120 wait_cmds_drained 14
8 set_flag 12
100 push_trigger 12
93 clear_flag 12
59 fade_sound 12
6 END_PHASE 12
9 read_freg 12
95 unit_hp_pct 9
115 named_event 9
39 MARK_LAST_PHASE 8
90 camera_at_route 8
17 wait_frames 6
10 random 6
123 timer_resume 5
40 mark_not_last 4
137 wait_units_ready 3
52 play_stream 3
14 play_bgm 3
62 FORCE_END_PHASE 3
127 timer_set 1
## named built-ins used, by traffic
11 end_coroutine 372
69 unit_state 255
1 start_coroutine 216
64 request_script_message 213
30 objective_marker 179
20 hp_pct_test 167
47 squadron_attack 137
18 dist_lt 92
5 kill_coroutine 83
70 unit_alive 71
56 unit_relation 52
4 wait_s 34
26 damage_unit 33
3 move_order 20
124 timer_stop 15
120 wait_cmds_drained 14
8 set_flag 12
100 reset_phase_threads 12
93 clear_flag 12
59 fade_sound 12
6 END_PHASE 12
9 read_freg 12
95 unit_hp_pct 9
115 named_event 9
48 squadron_escort 8
39 MARK_LAST_PHASE 8
90 camera_at_route 8
17 wait_frames 6
10 random 6
123 timer_resume 5
40 mark_not_last 4
137 wait_units_ready 3
52 play_stream 3
14 play_bgm 3
62 FORCE_END_PHASE 3
127 timer_set 1
## phase code bases
Each phase has its OWN base; the file header offset is not it.
0xe4 0x14aa8 0x24b4c
## disassembly into the first END_PHASE
resync from 0x5058
@@ -131,7 +140,7 @@ resync from 0x5058
0050CC: 02030C00 set.i len=12 k=02,03 00000010 00000000 local[16] = special[0]
0050D8: 01021001 set.f len=16 k=01,02 00000000 BFF00000 00000000 special[0] = imm -1
0050E8: 02030C01 set.f len=12 k=02,03 00000018 00000000 local[24] = special[0]
0050F4: 00000C13 call len=12 k=00,00 00000040 00000245 builtin64(0x42, 0x2, 0x1, 0x9, 0x1, -1)
0050F4: 00000C13 call len=12 k=00,00 00000040 00000245 request_script_message(0x42, 0x2, 0x1, 0x9, 0x1, -1)
005100: 0000080C jmp len=8 k=00,00 0000507C -> code+0x507C (file 0x50A0)
005108: 0000080C jmp len=8 k=00,00 0000507C -> code+0x507C (file 0x50A0)
005110: 01020C0A op10 len=12 k=01,02 00000000 00000000
@@ -153,13 +162,32 @@ resync from 0x5058
0051CC: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0]
0051D8: 00000C13 call len=12 k=00,00 00000004 0000024C wait_s(3)
0051E4: 00000C13 call len=12 k=00,00 00000006 0000024D END_PHASE
0051F0: 00000C13 call len=12 k=00,00 0000000B 0000024E yield
0051F0: 00000C13 call len=12 k=00,00 0000000B 0000024E end_coroutine
0051FC: 01030C00 set.i len=12 k=01,03 00000000 00000001 local[0] = imm 0x1
005208: 01030C00 set.i len=12 k=01,03 00000004 00000056 local[4] = imm 0x56
005214: 01021001 set.f len=16 k=01,02 00000000 00000000 00000000 special[0] = imm 0
005224: 02030C01 set.f len=12 k=02,03 00000008 00000000 local[8] = special[0]
005230: 00000C13 call len=12 k=00,00 00000014 00000252 hp_pct_test(0)
005230: 00000C13 call len=12 k=00,00 00000014 00000252 hp_pct_test(0x1, TCN004, 0)
00523C: 01020C0A op10 len=12 k=01,02 00000000 00000001
005248: 0000080E op14 len=8 k=00,00 0000575C
005250: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
00525C: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0]
005268: 00000C13 call len=12 k=00,00 00000074 00000253 builtin116(0x0)
005274: 00000C13 call len=12 k=00,00 00000065 00000254 builtin101
005280: 00000C13 call len=12 k=00,00 00000064 00000255 reset_phase_threads
00528C: 00000C13 call len=12 k=00,00 0000007C 00000256 timer_stop
005298: 01020C00 set.i len=12 k=01,02 00000000 FFFFFFFF special[0] = imm 0xFFFFFFFF
0052A4: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0]
0052B0: 00000C13 call len=12 k=00,00 0000005D 00000257 clear_flag(0xFFFFFFFF)
0052BC: 00000C13 call len=12 k=00,00 00000076 00000258 builtin118
0052C8: 00000C13 call len=12 k=00,00 00000027 0000025A MARK_LAST_PHASE
0052D4: 00000C13 call len=12 k=00,00 00000052 0000025B builtin82
0052E0: 01021001 set.f len=16 k=01,02 00000000 40100000 00000000 special[0] = imm 4
0052F0: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0]
0052FC: 00000C13 call len=12 k=00,00 00000004 0000025C wait_s(4)
005308: 01020C00 set.i len=12 k=01,02 00000000 00000005 special[0] = imm 0x5
005314: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0]
005320: 00000C13 call len=12 k=00,00 0000000A 0000025E random(0x5)
00532C: 0000080C jmp len=8 k=00,00 00005648 -> code+0x5648 (file 0x566C)
005334: 01020C00 set.i len=12 k=01,02 00000000 00000043 special[0] = imm 0x43
005340: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0]