diff --git a/docs/re/data/isl-command-table.txt b/docs/re/data/isl-command-table.txt new file mode 100644 index 00000000..e7841fb3 --- /dev/null +++ b/docs/re/data/isl-command-table.txt @@ -0,0 +1,69 @@ +# The ISL interpreter's command table — opcode -> handler +# +# Recovered by symbolically executing `sub_822FE040`, which fills 1023 eight-byte +# slots at `table+32` with a default and then overwrites individual ones. Slot +# index = (N - 32) / 8 from each `std r9, N(r31)`. +# +# Regenerate with `tools/re-capture/isl_cmdtab.py`. +# +# `82391BA8` is `li r3,1 ; blr` — an accept-and-discard stub. The opcodes bound +# to it are dead in this build: 768, 769, 774, 775, 776, 791, 792, 793, 805. +# +populated slots: 57 + opcode 256 -> 822FE8D0 + opcode 512 -> 822FE8D8 + opcode 513 -> 822FE9D8 + opcode 514 -> 822FE9C0 + opcode 515 -> 822FE9C8 + opcode 516 -> 822FE9D0 + opcode 517 -> 822FE8E0 + opcode 518 -> 822FE8E8 + opcode 519 -> 822FE9A0 + opcode 520 -> 822FF4C8 + opcode 768 -> 82391BA8 + opcode 769 -> 82391BA8 + opcode 772 -> 822FEDE0 + opcode 774 -> 82391BA8 + opcode 775 -> 82391BA8 + opcode 776 -> 82391BA8 + opcode 784 -> 822FEE28 + opcode 785 -> 822FEF00 + opcode 786 -> 822FEE38 + opcode 787 -> 822FEE30 + opcode 788 -> 822FEFB8 + opcode 789 -> 822FF060 + opcode 790 -> 822FF110 + opcode 791 -> 82391BA8 + opcode 792 -> 82391BA8 + opcode 793 -> 82391BA8 + opcode 800 -> 822FF118 + opcode 801 -> 822FF120 + opcode 802 -> 822FF128 + opcode 803 -> 822FF130 + opcode 804 -> 822FF1B8 + opcode 805 -> 82391BA8 + opcode 806 -> 822FF218 + opcode 807 -> 822FF220 + opcode 808 -> 822FF138 + opcode 816 -> 822FECC8 + opcode 817 -> 822FED10 + opcode 896 -> 822FF228 + opcode 897 -> 822FF280 + opcode 992 -> 822FF2D8 + opcode 993 -> 822FEDB0 + opcode 994 -> 822FEDC8 + opcode 995 -> 822FF330 + opcode 996 -> 822FF3B8 + opcode 997 -> 822FF468 + opcode 998 -> 822FF4A8 + opcode 999 -> 822FF4C0 + opcode 1008 -> 822FE9A8 + opcode 1009 -> 822FEA80 + opcode 1010 -> 822FEB10 + opcode 1011 -> 822FEB40 + opcode 1012 -> 822FEBB0 + opcode 1013 -> 822FEBB8 + opcode 1014 -> 822FEBD0 + opcode 1015 -> 822FEC20 + opcode 1016 -> 822FEB70 + opcode 1017 -> 822FEB98 diff --git a/docs/re/structures/isl-builtins.md b/docs/re/structures/isl-builtins.md index fa2cc8b6..8f1f9fc0 100644 --- a/docs/re/structures/isl-builtins.md +++ b/docs/re/structures/isl-builtins.md @@ -140,6 +140,39 @@ and spread checks but its maximum *exceeds* the table — flag indices run 0..31 against symbol tables as small as 40 — so it is excluded, and the disassembler now declines to resolve it rather than printing an invented name. +### ✅ The interpreter's command table, recovered + +`sub_822FE040` fills 1023 eight-byte slots at `table+32` with a default and then +overwrites individual ones; slot = `(N - 32) / 8` from each `std r9, N(r31)`. +Symbolically executing it yields **57 populated slots** — the full opcode → +handler map, committed as [`data/isl-command-table.txt`](../data/isl-command-table.txt) +and regenerable with `tools/re-capture/isl_cmdtab.py`. + +Nine opcodes point at `0x82391BA8`, which is `li r3,1 ; blr` — accept-and-discard. +**768, 769, 774, 775, 776, 791, 792, 793 and 805 are dead in this build**, which +is why the built-ins that post them do nothing. + +### ✅ Opcodes 800–802 send unit messages `0xED08 nn DE` + +Their table entries are thunks 8 bytes apart into handlers `0x823008C8`, +`0x823009B8`, `0x82300AA8` — each 60 instructions, and **differing in exactly two +words**: a descriptor offset and the message id. + +| opcode | built-in | unit message | +|---|---|---| +| 800 | 26 | **`0xED0802DE`** | +| 801 | **28** | **`0xED0803DE`** | +| 802 | **29**, 101 | **`0xED0804DE`** | + +That fixes the id format as `0xED08 nn DE`, and the ids already known from other +work fit it: opcode 514 → `00DE`, 803 → `07DE`, 999 → `0FDE`. + +🟡 The pump's arm for `0xED0802DE` does **not** apply an effect — it walks the +unit's child list at `[unit+320]`/`[unit+324]` and **rebroadcasts** to each child +as `0xED0902DE`. So `0xED08…` is the to-unit family and `0xED09…` the to-child +one, and the terminal effect is one link further on. ❌ Not followed; 26/28/29 +remain unnamed. + ### 🟡 Built-ins 26 / 28 / 29 are one family — and `damage_unit` looks mis-named Method-diffing put the structure beyond doubt but did not reach the semantics. diff --git a/tools/re-capture/isl_cmdtab.py b/tools/re-capture/isl_cmdtab.py new file mode 100644 index 00000000..d272e7d9 --- /dev/null +++ b/tools/re-capture/isl_cmdtab.py @@ -0,0 +1,52 @@ +"""Recover the ISL interpreter's 1023-slot command table from sub_822FE040. + +The builder fills every slot with a default, then overwrites individual slots. +Each write is `stw rX, off(r1)` (a two-word stack pair) followed by +`ld r9, off(r1)` and `std r9, N(r31)`, where slot = (N - 32) / 8. +""" +import duckdb, re, sys +con=duckdb.connect('/work/xenia-rs/sylpheed.db', read_only=True) +rows=con.execute("select address, coalesce(ext_disasm,disasm) from instructions " + "where address>=? and address %s %s" % (s, '%08X'%hi if hi else 'None', '%08X'%lo if lo else ''))