Verified rather than adopted: a subagent proposed that every even operand slot is a type tag. Measured, the strong form is false and a precise form is true. TRUE: a SYMBOL operand is two words, a tag holding the constant 1 followed by the index. Slot 0 is the integer 1 in 19899/19899 calls whose slot 4 is a unit; slot 8 is tag-shaped in 100% of calls for every built-in taking a second unit; slot 16 is 1 in 152/152 for built-in 128, the only one taking a third. The 24 built-ins whose slot 0 is NOT the constant are exactly those taking no symbol there. This explains the unit slots 4/12/20 rather than replacing them. FALSE as stated: slot 8 is a bare double for built-ins 4, 20, 24, 26, 28, 29, 90, 106 and 127, and built-in 75 carries five bare indices at 0/4/8/12/16 with no tags at all. Each built-in has a fixed signature and is 100% self-consistent; none of the 34 with >=20 sites mixes the two. Symbol table 1 has three types -- 1 routes (1362), 6 messages (2247), 7 effects (81) -- and its operand slots are type-pure, measured the same way. Resolving them makes listings say what the script means: `request_script_message(MSG_VOICE_D_257, ...)`, a fourth independent confirmation of that name. Slots 24@4, 46@12 and 114@4 resolve 100% but MIX types 6 and 1, so they are left unresolved rather than guessed. Two more names withdrawn, neither replaced: * 88 `camera_at` -- ZERO call sites in all 28 stages; never testable. * 90 `camera_at_route` -- 8 sites, all Stage 02 phase 3, first operand is symtab-1 type 7 `eff_n0071`, an EFFECT name, in 8/8, with a per-missile Route_ADT301..308_p3M at slot 20. Not aimed at a camera. Left unnamed on purpose: replacing a guessed name with another guess is how the three names corrected earlier today went wrong. Also flagged: 115 `named_event`'s only symbol operand is an eff_* name in 84/84 sites, so that name is suspect too. Not renamed pending a handler read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
73 lines
2.6 KiB
Python
73 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Regenerate the committed ISL artefacts under `docs/re/data/`.
|
|
|
|
isl_report.py <StageNN.ssb> calls -> the call-site census + a listing
|
|
|
|
The artefact was produced by an uncommitted one-off, so it drifted out of date
|
|
twice: once when operand staging was fixed (calls printed with too few
|
|
arguments) and once when three built-in names were corrected. Keeping the
|
|
generator in the tree is the point of this file.
|
|
|
|
`data/isl-stage02-conditions.txt` still has no generator here. A first attempt
|
|
is not committed because it printed most sites as bare `builtinN`: neither
|
|
`isl.resync` (it gives up far from a valid start) nor a naive linear decode from
|
|
the phase base reaches every call site, so producing that listing faithfully
|
|
needs the coroutine entry points, which `start_coroutine`'s operand carries and
|
|
this tool does not yet follow.
|
|
"""
|
|
import collections
|
|
import sys
|
|
|
|
import isl
|
|
|
|
def census(b):
|
|
cs = isl.call_sites(b)
|
|
return cs, collections.Counter(bid for _, bid, _ in cs)
|
|
|
|
|
|
def emit_calls(b, path):
|
|
cs, h = census(b)
|
|
s1, s2 = isl.symbols(b, 1), isl.symbols(b, 2)
|
|
print('# %s — ISL disassembly artefacts' % path)
|
|
print()
|
|
print('Generated by `tools/re-capture/isl_report.py calls`.')
|
|
print()
|
|
print('%d call sites, %d distinct built-ins' % (len(cs), len(h)))
|
|
for bid, n in h.most_common():
|
|
print(' builtin %-4d %5d site(s)' % (bid, n))
|
|
print()
|
|
print('## phase-control sites')
|
|
for bid, nm in ((6, 'END_PHASE'), (62, 'FORCE_END_PHASE'),
|
|
(39, 'MARK_LAST_PHASE'), (40, 'mark_not_last')):
|
|
offs = [off for off, b2, _ in cs if b2 == bid]
|
|
print('%-3d %-18s %2d: %s'
|
|
% (bid, nm, len(offs), ' '.join('0x%x' % o for o in offs)))
|
|
print()
|
|
print('## named built-ins used, by traffic')
|
|
for bid, n in h.most_common():
|
|
nm = isl.BUILTIN.get(bid)
|
|
if nm:
|
|
print(' %-3d %-24s %4d' % (bid, nm, n))
|
|
print()
|
|
print('## phase code bases')
|
|
print('Each phase has its OWN base; the file header offset is not it.')
|
|
print(' ' + ' '.join('0x%x' % x for x in isl.phase_bases(b)))
|
|
print()
|
|
print('## disassembly into the first END_PHASE')
|
|
target = [off for off, bid, _ in cs if bid == 6][0]
|
|
start = isl.resync(b, target)
|
|
print('resync from 0x%X' % start)
|
|
for line in isl.dis(b, start, 64, code_base=0x24, sym2=s2, sym1=s1):
|
|
print(line)
|
|
|
|
|
|
def main():
|
|
path = sys.argv[1]
|
|
b = isl.load(path)
|
|
name = path.replace('\\', '/').split('/')[-1]
|
|
{'calls': emit_calls}[sys.argv[2]](b, name)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|