diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index e9364512..014f9324 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -1387,9 +1387,20 @@ premise was wrong.** 🟡 **But `END_PHASE`'s call site is the WRONG place to read the condition:** all 12 Stage-02 `END_PHASE` sites sit in one stereotyped outro (`wait_cmds_drained → fade_sound(3) → builtin85(3) → wait_s(3) → END_PHASE → - end_coroutine`). ▶️ **Next, and it is now the only thing in the way: read the + end_coroutine`). ~~▶️ **Next, and it is now the only thing in the way: read the five branch handlers** `op10` (`0x82271598`), `op13` (`0x82271830`), `op14`, - `op21`, `op23`. The condition lives in the `op10`/`op13` poll loop upstream of + `op21`, `op23`.~~ ✅ **(2026-08-27) DONE for the branches — + [structures/isl-branches](structures/isl-branches.md).** `op10`/`op11` are + signed/float COMPARE, writing three condition bits (0=EQ, 1=GT, 2=LT) to a + bitset at `phase+24`; `op13`–`op18` are the six relational branches + `beq/bne/blt/ble/bgt/bge` on those bits, targeting `[phase+232] + word@+4` + exactly like `op12`. All six relations present, each once — the completeness is + the check. Handler addresses come from the `bl` inside each dispatcher thunk; + guessing them at a fixed stride lands mid-function. ▶️ **Still open:** `op23` + (`0x82271C30`, takes a built-in's result to `phase+168`) and `op21` + (`0x82175C20`) are characterised but NOT named, and naming the branch does not + yet give each stage's clear condition — that needs the operand chain feeding + each compare. The condition lives in the `op10`/`op13` poll loop upstream of the outro — e.g. phase 3 polls `unit_state(ADT308)` and branches back to `0xFEB4` until it passes. Artefact: `data/isl-stage02-phase-ends.txt`. * 🐛 **(2026-08-25) The nav fix is NOT fully reliable.** `dialog_up.py` works on diff --git a/docs/re/data/isl-stage02-phase-ends.txt b/docs/re/data/isl-stage02-phase-ends.txt index 9c6fc633..b2e7269f 100644 --- a/docs/re/data/isl-stage02-phase-ends.txt +++ b/docs/re/data/isl-stage02-phase-ends.txt @@ -8,12 +8,12 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 15 phase-ending call(s): 12 END_PHASE, 3 FORCE_END_PHASE ## phase 1 — builtin 6 (END_PHASE) at 0x51E4 - 005124: 01020C0A op10 len=12 k=01,02 00000000 00000001 - 005130: 0000080D op13 len=8 k=00,00 00004E2C - 005138: 01020C0A op10 len=12 k=01,02 00000000 00000002 - 005144: 0000080D op13 len=8 k=00,00 00004ED4 - 00514C: 01020C0A op10 len=12 k=01,02 00000000 00000003 - 005158: 0000080D op13 len=8 k=00,00 00004F7C + 005124: 01020C0A cmp.i len=12 k=01,02 00000000 00000001 + 005130: 0000080D beq len=8 k=00,00 00004E2C + 005138: 01020C0A cmp.i len=12 k=01,02 00000000 00000002 + 005144: 0000080D beq len=8 k=00,00 00004ED4 + 00514C: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 + 005158: 0000080D beq len=8 k=00,00 00004F7C 005160: 00000C13 call len=12 k=00,00 00000078 00000248 wait_cmds_drained 00516C: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 00517C: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -32,12 +32,12 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 005224: 02030C01 set.f len=12 k=02,03 00000008 00000000 local[8] = special[0] ## phase 1 — builtin 6 (END_PHASE) at 0x5828 - 005768: 01020C0A op10 len=12 k=01,02 00000000 00000003 - 005774: 0000080D op13 len=8 k=00,00 00005448 - 00577C: 01020C0A op10 len=12 k=01,02 00000000 00000004 - 005788: 0000080D op13 len=8 k=00,00 000054F0 - 005790: 01020C0A op10 len=12 k=01,02 00000000 00000005 - 00579C: 0000080D op13 len=8 k=00,00 00005598 + 005768: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 + 005774: 0000080D beq len=8 k=00,00 00005448 + 00577C: 01020C0A cmp.i len=12 k=01,02 00000000 00000004 + 005788: 0000080D beq len=8 k=00,00 000054F0 + 005790: 01020C0A cmp.i len=12 k=01,02 00000000 00000005 + 00579C: 0000080D beq len=8 k=00,00 00005598 0057A4: 00000C13 call len=12 k=00,00 00000078 00000272 wait_cmds_drained 0057B0: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 0057C0: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -128,12 +128,12 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 014858: 0000081A op26? len=8 k=00,00 00000000 ## phase 2 — builtin 6 (END_PHASE) at 0x19640 - 019580: 01020C0A op10 len=12 k=01,02 00000000 00000001 - 01958C: 0000080D op13 len=8 k=00,00 000048C4 - 019594: 01020C0A op10 len=12 k=01,02 00000000 00000002 - 0195A0: 0000080D op13 len=8 k=00,00 0000496C - 0195A8: 01020C0A op10 len=12 k=01,02 00000000 00000003 - 0195B4: 0000080D op13 len=8 k=00,00 00004A14 + 019580: 01020C0A cmp.i len=12 k=01,02 00000000 00000001 + 01958C: 0000080D beq len=8 k=00,00 000048C4 + 019594: 01020C0A cmp.i len=12 k=01,02 00000000 00000002 + 0195A0: 0000080D beq len=8 k=00,00 0000496C + 0195A8: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 + 0195B4: 0000080D beq len=8 k=00,00 00004A14 0195BC: 00000C13 call len=12 k=00,00 00000078 00000204 wait_cmds_drained 0195C8: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 0195D8: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -200,7 +200,7 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 01AC74: 01030C00 set.i len=12 k=01,03 00000000 00000001 local[0] = imm 0x1 ## phase 2 — builtin 62 (FORCE_END_PHASE) at 0x249F0 - 024938: 0000080E op14 len=8 k=00,00 0000FF44 + 024938: 0000080E bne len=8 k=00,00 0000FF44 024940: 01020C00 set.i len=12 k=01,02 00000000 000000F1 special[0] = imm 0xF1 02494C: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0] 024958: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0 @@ -224,12 +224,12 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 024A1C: 0000081A op26? len=8 k=00,00 00000000 ## phase 3 — builtin 6 (END_PHASE) at 0x2B96C - 02B8AC: 01020C0A op10 len=12 k=01,02 00000000 00000001 - 02B8B8: 0000080D op13 len=8 k=00,00 00006B4C - 02B8C0: 01020C0A op10 len=12 k=01,02 00000000 00000002 - 02B8CC: 0000080D op13 len=8 k=00,00 00006BF4 - 02B8D4: 01020C0A op10 len=12 k=01,02 00000000 00000003 - 02B8E0: 0000080D op13 len=8 k=00,00 00006C9C + 02B8AC: 01020C0A cmp.i len=12 k=01,02 00000000 00000001 + 02B8B8: 0000080D beq len=8 k=00,00 00006B4C + 02B8C0: 01020C0A cmp.i len=12 k=01,02 00000000 00000002 + 02B8CC: 0000080D beq len=8 k=00,00 00006BF4 + 02B8D4: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 + 02B8E0: 0000080D beq len=8 k=00,00 00006C9C 02B8E8: 00000C13 call len=12 k=00,00 00000078 00000270 wait_cmds_drained 02B8F4: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 02B904: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -248,12 +248,12 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 02B9AC: 02030C01 set.f len=12 k=02,03 00000008 00000000 local[8] = special[0] ## phase 3 — builtin 6 (END_PHASE) at 0x2BFB0 - 02BEF0: 01020C0A op10 len=12 k=01,02 00000000 00000003 - 02BEFC: 0000080D op13 len=8 k=00,00 00007168 - 02BF04: 01020C0A op10 len=12 k=01,02 00000000 00000004 - 02BF10: 0000080D op13 len=8 k=00,00 00007210 - 02BF18: 01020C0A op10 len=12 k=01,02 00000000 00000005 - 02BF24: 0000080D op13 len=8 k=00,00 000072B8 + 02BEF0: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 + 02BEFC: 0000080D beq len=8 k=00,00 00007168 + 02BF04: 01020C0A cmp.i len=12 k=01,02 00000000 00000004 + 02BF10: 0000080D beq len=8 k=00,00 00007210 + 02BF18: 01020C0A cmp.i len=12 k=01,02 00000000 00000005 + 02BF24: 0000080D beq len=8 k=00,00 000072B8 02BF2C: 00000C13 call len=12 k=00,00 00000078 0000029A wait_cmds_drained 02BF38: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 02BF48: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -266,8 +266,8 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 02BFA4: 00000C13 call len=12 k=00,00 00000004 0000029E wait_s(3) 02BFB0: 00000C13 call len=12 k=00,00 00000006 0000029F END_PHASE 02BFBC: 00000C13 call len=12 k=00,00 0000000B 000002A0 end_coroutine - 02BFC8: 01000C0A op10 len=12 k=01,00 00000070 00000004 - 02BFD4: 0000080F op15 len=8 k=00,00 000076AC + 02BFC8: 01000C0A cmp.i len=12 k=01,00 00000070 00000004 + 02BFD4: 0000080F blt len=8 k=00,00 000076AC 02BFDC: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0 02BFE8: 02030C00 set.i len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -300,8 +300,8 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 02CEC8: 02000415 op21 len=4 k=02,00 02CECC: 00000C13 call len=12 k=00,00 00000063 00000306 builtin99 02CED8: 00020417 op23 len=4 k=00,02 - 02CEDC: 02020C0A op10 len=12 k=02,02 00000000 00000001 - 02CEE8: 0000080D op13 len=8 k=00,00 000083B0 + 02CEDC: 02020C0A cmp.i len=12 k=02,02 00000000 00000001 + 02CEE8: 0000080D beq len=8 k=00,00 000083B0 02CEF0: 01000C00 set.i len=12 k=01,00 00000074 00000002 global[116] = imm 0x2 02CEFC: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 02CF0C: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -344,10 +344,10 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 02D210: 01021001 set.f len=16 k=01,02 00000000 00000000 00000000 special[0] = imm 0 ## phase 3 — builtin 62 (FORCE_END_PHASE) at 0x34A10 - 034974: 0000080D op13 len=8 k=00,00 0000FE3C + 034974: 0000080D beq len=8 k=00,00 0000FE3C 03497C: 00000C13 call len=12 k=00,00 0000000B 00000728 end_coroutine - 034988: 01000C0A op10 len=12 k=01,00 00000014 00000007 - 034994: 0000080E op14 len=8 k=00,00 0000FEB4 + 034988: 01000C0A cmp.i len=12 k=01,00 00000014 00000007 + 034994: 0000080E bne len=8 k=00,00 0000FEB4 03499C: 01020C00 set.i len=12 k=01,02 00000000 00000001 special[0] = imm 0x1 0349A8: 02020C00 set.i len=12 k=02,02 00000001 00000000 special[1] = special[0] 0349B4: 02000415 op21 len=4 k=02,00 @@ -355,8 +355,8 @@ phase code bases: 0xe4 0x14aa8 0x24b4c 0349C4: 01030C00 set.i len=12 k=01,03 00000004 00000049 local[4] = imm 0x49 0349D0: 00000C13 call len=12 k=00,00 00000045 0000072C unit_state(ADT308) 0349DC: 00020417 op23 len=4 k=00,02 - 0349E0: 02020C0A op10 len=12 k=02,02 00000000 00000001 - 0349EC: 0000080D op13 len=8 k=00,00 0000FEB4 + 0349E0: 02020C0A cmp.i len=12 k=02,02 00000000 00000001 + 0349EC: 0000080D beq len=8 k=00,00 0000FEB4 0349F4: 00000C13 call len=12 k=00,00 0000000B 0000072D end_coroutine 034A00: 00000C13 call len=12 k=00,00 0000000B 00000731 end_coroutine 034A0C: 00000414 ret len=4 k=00,00 diff --git a/docs/re/data/isl-stage02.txt b/docs/re/data/isl-stage02.txt index bf295ea4..b87a082e 100644 --- a/docs/re/data/isl-stage02.txt +++ b/docs/re/data/isl-stage02.txt @@ -150,14 +150,14 @@ resync from 0x5058 0050F4: 00000C13 call len=12 k=00,00 00000040 00000245 request_script_message(MSG_VOICE_D_257, 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 -00511C: 0000080D op13 len=8 k=00,00 00004D84 -005124: 01020C0A op10 len=12 k=01,02 00000000 00000001 -005130: 0000080D op13 len=8 k=00,00 00004E2C -005138: 01020C0A op10 len=12 k=01,02 00000000 00000002 -005144: 0000080D op13 len=8 k=00,00 00004ED4 -00514C: 01020C0A op10 len=12 k=01,02 00000000 00000003 -005158: 0000080D op13 len=8 k=00,00 00004F7C +005110: 01020C0A cmp.i len=12 k=01,02 00000000 00000000 +00511C: 0000080D beq len=8 k=00,00 00004D84 +005124: 01020C0A cmp.i len=12 k=01,02 00000000 00000001 +005130: 0000080D beq len=8 k=00,00 00004E2C +005138: 01020C0A cmp.i len=12 k=01,02 00000000 00000002 +005144: 0000080D beq len=8 k=00,00 00004ED4 +00514C: 01020C0A cmp.i len=12 k=01,02 00000000 00000003 +005158: 0000080D beq len=8 k=00,00 00004F7C 005160: 00000C13 call len=12 k=00,00 00000078 00000248 wait_cmds_drained 00516C: 01021001 set.f len=16 k=01,02 00000000 40080000 00000000 special[0] = imm 3 00517C: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] @@ -175,8 +175,8 @@ resync from 0x5058 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(TCN004, 0) -00523C: 01020C0A op10 len=12 k=01,02 00000000 00000001 -005248: 0000080E op14 len=8 k=00,00 0000575C +00523C: 01020C0A cmp.i len=12 k=01,02 00000000 00000001 +005248: 0000080E bne 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) diff --git a/docs/re/structures/isl-branches.md b/docs/re/structures/isl-branches.md new file mode 100644 index 00000000..209b3645 --- /dev/null +++ b/docs/re/structures/isl-branches.md @@ -0,0 +1,138 @@ +# ✅ The ISL branch ops — a condition-code machine, read off the handlers + +[`BACKLOG.md`](../BACKLOG.md) had this as the last thing between the flat decode +and a per-phase clear condition: five unread handlers, and an explicit +instruction not to name a branch from a pattern. They are read now, from +`sylpheed.db`. Nothing below is inferred from usage. + +## Getting the real handler addresses + +The 25-entry jump table at `0x822635FC` holds **thunks** inside the dispatcher, +not the handlers. Each thunk is three register moves and a `bl`; the `bl` target +is the handler. Taking the addresses any other way gets them wrong — my first +attempt guessed them at a fixed stride and landed mid-function, which produced a +20-line "difference" that was pure misalignment. + +| op | thunk | handler | +|---|---|---| +| 10 | `0x822636F8` | `0x82271598` | +| 11 | `0x8226370C` | `0x822716E0` | +| 12 | `0x82263720` | *inline in the thunk* | +| 13 | `0x82263738` | `0x82271830` | +| 14 | `0x8226374C` | `0x822718C8` | +| 15 | `0x82263760` | `0x82271960` | +| 16 | `0x82263774` | `0x822719F8` | +| 17 | `0x8226379C` | `0x82271AC8` | +| 18 | `0x82263788` | `0x82271B60` | + +## ✅ op10 / op11 are COMPARE, and they write three condition bits + +`0x82271598` resolves two operands and compares them: + +``` +822715B0 lwz r5, 8(r29) ; word@+8 +822715B4 lbz r4, 0(r29) ; kind byte[0] +822715B8 bl 0x82271D40 ; integer operand resolver -> r28 = RHS +822715C0 lwz r5, 4(r29) ; word@+4 +822715C8 lbz r4, 1(r29) ; kind byte[1] +822715CC bl 0x82271D40 -> r27 = LHS +822715D4 addi r31, r31, 24 ; the condition bitset lives at phase+24 +822715D8 cmp cr6, 0, r27, r28 ; SIGNED +``` + +It then writes **three** bits, each set-or-cleared by its own `cmp`: + +| bit | written at | condition | set / clear | +|---|---|---|---| +| **0** | `0x822715D8` | `EQ` | `or` if equal, `andc` if not | +| **1** | `0x8227162C` | `GT` | `or` / `andc` on `cr6+gt` | +| **2** | `0x82271678` | `LT` | `or` / `andc` on `cr6+lt` | + +**`op11` is the same machine for floats** — `0x822716E0` resolves through the +float resolvers (`0x82271F10` / `0x82271E30`), issues `fcmpu cr6, f30, f31`, and +writes the same bitset at `phase+24`. + +**Operand order matters and is easy to get backwards:** LHS is `(kind byte[1], +word@+4)` and RHS is `(kind byte[0], word@+8)`. So a listing line + +``` +cmp.i k=01,02 00000000 00000002 +``` + +is *compare `special[0]` against immediate `2`* — `k=01` is the RHS kind +(`imm`), `k=02` the LHS kind (`special`). + +## ✅ op13–op18 are the six relational branches + +Every one of them tests bits in that same bitset and, when taken, sets the pc to +`[phase+232] + word@+4` — **the identical phase-relative target form as the +unconditional `op12`**. + +| op | bits tested | taken when | name | +|---|---|---|---| +| 13 | 0 | set | **`beq`** | +| 14 | 0 | clear | **`bne`** | +| 15 | 2 | set | **`blt`** | +| 17 | 1 | set | **`bgt`** | +| 16 | 2, then 0 | either set | **`ble`** | +| 18 | 1, then 0 | either set | **`bge`** | + +13, 14, 15 and 17 are **byte-identical to each other** apart from two +instructions — the bit index (`addi r5, r0, N`) and the polarity +(`cmpli r11, 0x1` vs `0x0`). 16 and 18 are longer because they test a second bit +after the first fails, which is exactly `<=` and `>=`. + +🔑 **All six relations are present and each appears exactly once.** That +completeness is the check: a mis-read would not produce a closed, non-redundant +relational set. + +## ✅ This closes the `op10`+`op13` "switch" question + +[`isl-builtins.md`](isl-builtins.md) recorded it as 🟡 *"Consecutive small +immediates each paired with their own code offset is the shape of a case/branch +dispatch … **Not confirmed** — the handlers have not been read."* They are read +now, and the shape is what it looked like — a chain of compare-and-branch-if-equal: + +``` +cmp.i k=01,02 00000000 00000001 +beq -> 0x4E2C +cmp.i k=01,02 00000000 00000002 +beq -> 0x4ED4 +cmp.i k=01,02 00000000 00000003 +beq -> 0x4F7C +``` + +*"switch (special[0]) { case 1: … case 2: … case 3: … }"*, lowered to sequential +compares. Confirmed from the handlers, not from the pattern. + +## ✅ And a phase-3 clear condition now reads as one + +From [`../data/isl-stage02-phase-ends.txt`](../data/isl-stage02-phase-ends.txt): + +``` +0349D0 call unit_state(ADT308) +0349DC op23 ; takes the call result +0349E0 cmp.i k=02,02 special[0], special[1] +0349EC beq -> 0xFEB4 ; loop back while it holds +0349F4 call end_coroutine +``` + +A coroutine polling `unit_state` on unit `ADT308` and branching **back** while +the comparison is equal — the poll loop the previous iteration could only +describe by shape. + +## 🟡 Not settled + +* **`op23`** (`0x82271C30`) is left unnamed. It indexes a container at `r3+44` + and stores a word to `[phase+168]`; it is almost certainly how a built-in's + return value reaches `special[]`, but "almost certainly" is how this corpus + acquired two names it later had to withdraw. Characterised, not named. +* **`op21`** (`0x82175C20`) has a different shape from all of these — its thunk + passes `phase+168` and `phase+44`, not the pc — and was not read. +* **The bitset container at `phase+24`.** `op10` reaches it with `0x822749B0` + (by address, `phase+24`) and `op13` with `0x82274CC0` (through a word loaded + from `phase+32`). Both land on the same bits, but the exact container layout + is not established, so `phase+32` is *not* asserted to be its data pointer. +* **Which value `special[0]` holds at a given site.** Naming the branch does not + by itself give the clear condition for every stage — that needs the operand + chain feeding each compare, which is the next step. diff --git a/docs/re/structures/isl-builtins.md b/docs/re/structures/isl-builtins.md index 71b3d02e..f3d8ee70 100644 --- a/docs/re/structures/isl-builtins.md +++ b/docs/re/structures/isl-builtins.md @@ -704,9 +704,15 @@ op13 -> 0x5598 Consecutive small immediates each paired with their own code offset is the shape of a **case/branch dispatch**, and `op12` is already confirmed as the -unconditional jump. **Not confirmed** — the handlers (`0x82271598` for op10, +unconditional jump. ~~**Not confirmed** — the handlers (`0x82271598` for op10, `0x82271830` for op13) have not been read, and I am not going to name them from -a pattern alone. +a pattern alone.~~ +✅ **(2026-08-27) CONFIRMED from the handlers — see +[isl-branches](isl-branches.md).** `op10` is a signed compare writing three +condition bits (0=EQ, 1=GT, 2=LT) to a bitset at `phase+24`; `op11` is the float +twin via `fcmpu`; `op13`–`op18` are the six relational branches +(`beq bne blt ble bgt bge`) on those bits, targeting `[phase+232] + word@+4` +like `op12`. It is a case dispatch lowered to sequential compare-and-branch. ## 🔴 Correction: `unit_state` does NOT read `+16` — it reads `+4` and `+104` diff --git a/tools/re-capture/isl.py b/tools/re-capture/isl.py index 33c00e74..40508a77 100755 --- a/tools/re-capture/isl.py +++ b/tools/re-capture/isl.py @@ -73,6 +73,14 @@ CODE_BASE_FIELD = 0x08 # .ssb header: code offset (0x24 in every file) # opcode -> (mnemonic, handler VA) from the jump table KIND = {0: 'global', 1: 'imm', 2: 'special', 3: 'local'} +# op10 `cmp.i` resolves its two operands as +# LHS = resolve(kind byte[1], word@+4) `lbz r4,1(pc)` + `lwz r5,4(pc)` +# RHS = resolve(kind byte[0], word@+8) `lbz r4,0(pc)` + `lwz r5,8(pc)` +# and issues a SIGNED `cmp cr6, 0, LHS, RHS`. op11 `cmp.f` is the same shape +# through the float resolvers with `fcmpu`. So a listing line +# cmp.i k=01,02 00000000 00000002 +# reads LHS = special[0], RHS = imm 2 -- "compare special[0] with 2". + # Built-in names, from the 147-entry table at 0x8227226C. Only the ones whose # handler was actually read are named; the rest print as a bare id rather than a # guess. See docs/re/structures/isl-builtins.md. @@ -114,8 +122,15 @@ OPS = { 0: 'set.i', 1: 'set.f', 2: 'cmp.a', 4: 'cmp.a', 6: 'cmp.a', 8: 'cmp.a', 3: 'cmp.b', 5: 'cmp.b', 7: 'cmp.b', 9: 'cmp.b', - 10: 'op10', 11: 'op11', 12: 'jmp', 13: 'op13', 14: 'op14', 15: 'op15', - 16: 'op16', 17: 'op17', 18: 'op18', 19: 'call', 20: 'ret', + # 10-18: a condition-code architecture, read off the handlers. op10/op11 + # COMPARE and write three bits into a bitset at `phase+24` + # bit 0 = EQ bit 1 = GT bit 2 = LT + # and 13-18 branch on those bits to `[phase+232] + word@+4` -- the same + # phase-relative target form as the unconditional op12. All six relations + # are present, which is itself the check that the reading is right. + 10: 'cmp.i', 11: 'cmp.f', 12: 'jmp', + 13: 'beq', 14: 'bne', 15: 'blt', 16: 'ble', 17: 'bgt', 18: 'bge', + 19: 'call', 20: 'ret', 21: 'op21', 22: 'op22', 23: 'op23', 24: 'op24', }