diff --git a/docs/backlog.md b/docs/backlog.md
index 2a96dba7c..b1a0f8491 100644
--- a/docs/backlog.md
+++ b/docs/backlog.md
@@ -2,7 +2,7 @@
> Generated by `tools/backlog.py render` from `.run/backlog.jsonl`. These are functions the Phase-21 automation got **close** on but did NOT byte-match. The whole-binary byte-gate is the sole arbiter (G3/P9): **byte-matches bank and are NOT listed here** — only genuine near-misses/blockers are. Ranked by hand-session priority: **reach** (×N propagation leverage) → **closeness** (match_one mismatch count, lower = closer) → **size**. Each row's `best_draft` is the closest C the machine reached — resume from there.
-**Open near-misses:** 863 · by status {'near': 825, 'failed': 38} · by class {'schedule': 4, 'plumbing': 6, 'struct': 11, 'regalloc-order': 9, None: 827, 'other': 1, 'WAVE': 3, 'STRUCT': 1, 'loose-typing': 1}
+**Open near-misses:** 862 · by status {'near': 824, 'failed': 38} · by class {'schedule': 4, 'plumbing': 6, 'struct': 11, 'regalloc-order': 9, None: 826, 'other': 1, 'WAVE': 3, 'STRUCT': 1, 'loose-typing': 1}
| # | addr | reach | class | nins | status | closeness | where it stuck | best draft |
|--:|------|------:|-------|-----:|--------|----------:|----------------|------------|
@@ -826,46 +826,45 @@
| 818 | func_80183BF8 | None | | None | near | 258 | residual: 258 mismatch | `.run/backlog_drafts/func_80183BF8.c` |
| 819 | func_8017EB30 | None | | None | near | 278 | residual: 278 mismatch | `.run/backlog_drafts/func_8017EB30.c` |
| 820 | func_801804A0 | None | | None | near | 280 | residual: 280 mismatch | `.run/backlog_drafts/func_801804A0.c` |
-| 821 | func_80187EDC | None | | None | near | 296 | residual: 296 mismatch | `.run/backlog_drafts/func_80187EDC.c` |
-| 822 | func_8017F554 | None | | None | near | 299 | residual: 299 mismatch | `.run/backlog_drafts/func_8017F554.c` |
-| 823 | func_80181670 | None | | None | near | 311 | residual: 311 mismatch | `.run/backlog_drafts/func_80181670.c` |
-| 824 | func_8017EA84 | None | | None | near | 578 | residual: 578 mismatch | `.run/backlog_drafts/func_8017EA84.c` |
-| 825 | func_8018057C | None | | None | near | 897 | residual: 897 mismatch | `.run/backlog_drafts/func_8018057C.c` |
-| 826 | func_80184A68 | 1 | regalloc-order | 33 | failed | | none — MATCH | `.run/backlog_drafts/func_80184A68.c` |
-| 827 | func_80180B64 | 1 | struct | 75 | failed | | none — MATCH (75 ins, relocation-masked) | `.run/backlog_drafts/func_80180B64.c` |
-| 828 | func_80183DE0 | 1 | regalloc-order | 91 | failed | | testing if(!=1) layout + counter-before-pointer init order | `.run/backlog_drafts/func_80183DE0.c` |
-| 829 | func_80182C9C | 1 | schedule | 101 | failed | | none — MATCH (101 ins). Inner-switch break-to-shared-tail must be written as | `.run/backlog_drafts/func_80182C9C.c` |
-| 830 | func_80183FB8 | 1 | loose-typing | 101 | failed | | none — MATCH (relocation-masked match_one, 101/101 ins) | `.run/backlog_drafts/func_80183FB8.c` |
-| 831 | func_80185BA4 | 1 | WAVE | 177 | failed | | won't compile standalone (loose-typing / missing decl) | |
-| 832 | func_8017D8DC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017D8DC.c` |
-| 833 | func_8017FFEC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFEC.c` |
-| 834 | func_8017DC18 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DC18.c` |
-| 835 | func_801853CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801853CC.c` |
-| 836 | func_80181894 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181894.c` |
-| 837 | func_8018BFBC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018BFBC.c` |
-| 838 | func_801807F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801807F4.c` |
-| 839 | func_8017FFC8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC8.c` |
-| 840 | func_8017E99C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E99C.c` |
-| 841 | func_80180294 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80180294.c` |
-| 842 | func_8017E76C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E76C.c` |
-| 843 | func_8017F29C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F29C.c` |
-| 844 | func_8017F00C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F00C.c` |
-| 845 | func_801802B0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801802B0.c` |
-| 846 | func_8017DA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DA1C.c` |
-| 847 | func_8017FFC4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC4.c` |
-| 848 | func_8017E2F0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E2F0.c` |
-| 849 | func_801841E4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801841E4.c` |
-| 850 | func_80181738 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181738.c` |
-| 851 | func_801873D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801873D8.c` |
-| 852 | func_80185628 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185628.c` |
-| 853 | func_80181A78 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181A78.c` |
-| 854 | func_801805D4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801805D4.c` |
-| 855 | func_8017EA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017EA1C.c` |
-| 856 | func_8017F098 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F098.c` |
-| 857 | func_801822CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801822CC.c` |
-| 858 | func_8017E3F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E3F4.c` |
-| 859 | func_800D1658 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1658.c` |
-| 860 | func_800D1984 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1984.c` |
-| 861 | func_800D24A0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D24A0.c` |
-| 862 | func_80144B9C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80144B9C.c` |
-| 863 | func_8013DD68 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8013DD68.c` |
+| 821 | func_8017F554 | None | | None | near | 299 | residual: 299 mismatch | `.run/backlog_drafts/func_8017F554.c` |
+| 822 | func_80181670 | None | | None | near | 311 | residual: 311 mismatch | `.run/backlog_drafts/func_80181670.c` |
+| 823 | func_8017EA84 | None | | None | near | 578 | residual: 578 mismatch | `.run/backlog_drafts/func_8017EA84.c` |
+| 824 | func_8018057C | None | | None | near | 897 | residual: 897 mismatch | `.run/backlog_drafts/func_8018057C.c` |
+| 825 | func_80184A68 | 1 | regalloc-order | 33 | failed | | none — MATCH | `.run/backlog_drafts/func_80184A68.c` |
+| 826 | func_80180B64 | 1 | struct | 75 | failed | | none — MATCH (75 ins, relocation-masked) | `.run/backlog_drafts/func_80180B64.c` |
+| 827 | func_80183DE0 | 1 | regalloc-order | 91 | failed | | testing if(!=1) layout + counter-before-pointer init order | `.run/backlog_drafts/func_80183DE0.c` |
+| 828 | func_80182C9C | 1 | schedule | 101 | failed | | none — MATCH (101 ins). Inner-switch break-to-shared-tail must be written as | `.run/backlog_drafts/func_80182C9C.c` |
+| 829 | func_80183FB8 | 1 | loose-typing | 101 | failed | | none — MATCH (relocation-masked match_one, 101/101 ins) | `.run/backlog_drafts/func_80183FB8.c` |
+| 830 | func_80185BA4 | 1 | WAVE | 177 | failed | | won't compile standalone (loose-typing / missing decl) | |
+| 831 | func_8017D8DC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017D8DC.c` |
+| 832 | func_8017FFEC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFEC.c` |
+| 833 | func_8017DC18 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DC18.c` |
+| 834 | func_801853CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801853CC.c` |
+| 835 | func_80181894 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181894.c` |
+| 836 | func_8018BFBC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018BFBC.c` |
+| 837 | func_801807F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801807F4.c` |
+| 838 | func_8017FFC8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC8.c` |
+| 839 | func_8017E99C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E99C.c` |
+| 840 | func_80180294 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80180294.c` |
+| 841 | func_8017E76C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E76C.c` |
+| 842 | func_8017F29C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F29C.c` |
+| 843 | func_8017F00C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F00C.c` |
+| 844 | func_801802B0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801802B0.c` |
+| 845 | func_8017DA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DA1C.c` |
+| 846 | func_8017FFC4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC4.c` |
+| 847 | func_8017E2F0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E2F0.c` |
+| 848 | func_801841E4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801841E4.c` |
+| 849 | func_80181738 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181738.c` |
+| 850 | func_801873D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801873D8.c` |
+| 851 | func_80185628 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185628.c` |
+| 852 | func_80181A78 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181A78.c` |
+| 853 | func_801805D4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801805D4.c` |
+| 854 | func_8017EA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017EA1C.c` |
+| 855 | func_8017F098 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F098.c` |
+| 856 | func_801822CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801822CC.c` |
+| 857 | func_8017E3F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E3F4.c` |
+| 858 | func_800D1658 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1658.c` |
+| 859 | func_800D1984 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1984.c` |
+| 860 | func_800D24A0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D24A0.c` |
+| 861 | func_80144B9C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80144B9C.c` |
+| 862 | func_8013DD68 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8013DD68.c` |
diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md
index c1c5c3393..131c99481 100644
--- a/docs/cookbook-index.md
+++ b/docs/cookbook-index.md
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
-> `docs/matching-cookbook.md` is ~716 KB / 389 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
+> `docs/matching-cookbook.md` is ~716 KB / 390 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -225,7 +225,7 @@
- **§3-The** — declaration surface (integration, not codegen) L8931
- **§136f** — Two declaration sub-cases the reconcile lane surfaced (lane now 15/15 lifetime) L9176
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius L9405
-- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9536
+- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9555
### jump tables & switches (25)
@@ -377,7 +377,7 @@
- **§114** — The THIRD decl axis: a CALLEE the draft declares differently from the target TU (Phase 29 T76/T77) L7801
- **§3-The** — integration idioms (these decide whether a byte-correct draft BANKS) L8797
- **§3-The** — declaration surface (integration, not codegen) L8931
-- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9536
+- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9555
### build graph, splat & the harness (95)
@@ -475,7 +475,7 @@
- **§137a** — A gate verdict has a TIMESTAMP; re-check it against the draft's mtime L9376
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius L9405
- **§134** — again, in a second tool — and the waiter rule corrected L9516
-- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9536
+- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9555
### process, measurement & doctrine (53)
@@ -533,7 +533,7 @@
- **§136j** — The failure MIX flips with function size (measured across four bands, one session) L9292
- **Rank** — the lane by measured concentration, not by class count L9471
-### (unbucketed — title matched no symptom vocabulary) (109)
+### (unbucketed — title matched no symptom vocabulary) (110)
- **§3-How** — to use this L30
- **§1** — Idiom catalog (asm pattern → C that produces it) L39
@@ -644,6 +644,7 @@
- **§136i** — The drafter model LADDER: Haiku → **Sonnet** → Opus → Fable5 (Drew, 2026-08-03) L9260
- **§3-The** — triage, cheapest first L9411
- **THREE** — carry variants hide in one "CARRY-FIXABLE" bucket — and they need different fixes L9480
+- **STEP** — 0 of sibling-first: grep `src/` for a distinctive LITERAL from the `.s` L9536
## All sections, in order
@@ -1036,4 +1037,5 @@
- **Rank** — the lane by measured concentration, not by class count L9471
- **THREE** — carry variants hide in one "CARRY-FIXABLE" bucket — and they need different fixes L9480
- **§134** — again, in a second tool — and the waiter rule corrected L9516
-- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9536
+- **STEP** — 0 of sibling-first: grep `src/` for a distinctive LITERAL from the `.s` L9536
+- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9555
diff --git a/docs/family-hseq.md b/docs/family-hseq.md
index d1cde2ec5..2cf8616f0 100644
--- a/docs/family-hseq.md
+++ b/docs/family-hseq.md
@@ -2,13 +2,13 @@
> Generated by `tools/family_hseq.py` from the 138 overlay sigs + per-overlay src stubs. Ranked by TEMPLATABLE byte-weight (PURE+IMM members × nins × 4). The byte-gate is the arbiter.
>
-> **Scope: the 138 OVERLAYS only** (no main, no resident) · generated at HEAD `commit:1386` · stub set derived from `corpus.stubs` — the same oracle `progress.py` counts, so same-tree overlay totals agree by construction; compare digests only at the same HEAD.
+> **Scope: the 138 OVERLAYS only** (no main, no resident) · generated at HEAD `commit:1387` · stub set derived from `corpus.stubs` — the same oracle `progress.py` counts, so same-tree overlay totals agree by construction; compare digests only at the same HEAD.
-**Fleet (overlays):** 96.5% fn / 94.4% instr / 89.3% distinct-code matched. Unmatched: 12,264 instances / 736,631 ins (9,820 distinct classes).
+**Fleet (overlays):** 96.5% fn / 94.4% instr / 89.4% distinct-code matched. Unmatched: 12,230 instances / 730,269 ins (9,790 distinct classes).
-**Tail cross-check (Phase-25 close):** 8,013 tail fns / 392,543 ins → 434 h_seq families ≥2, **111 substantial (nins≥80) / 88,803 ins**.
+**Tail cross-check (Phase-25 close):** 7,867 tail fns / 390,989 ins → 433 h_seq families ≥2, **110 substantial (nins≥80) / 87,350 ins**.
-**Full frontier (all unmatched by h_seq):** 2044 target families (≥2 members or a matched sibling) + 3767 singletons (Step-D residue). Substantial: **381 families / 274,821 templatable ins**, 30 with a matched sibling (zero-crack). Substantial member classes: 1,625 PURE · 29 IMM · 6 STRUCT-excluded.
+**Full frontier (all unmatched by h_seq):** 2041 target families (≥2 members or a matched sibling) + 3767 singletons (Step-D residue). Substantial: **378 families / 268,604 templatable ins**, 28 with a matched sibling (zero-crack). Substantial member classes: 1,595 PURE · 28 IMM · 6 STRUCT-excluded.
## Top substantial families (by templatable byte-weight)
@@ -21,47 +21,47 @@
| 4 | 299 | 20 (20/0/0) | 20/20 | scattered | PURE | 0 | Y | 0x8017fee0 modal | 5,980 |
| 5 | 246 | 16 (16/0/0) | 6/16 | cross-address | PURE | 0 | · | 0x8017c294 draft-ov077 | 3,936 |
| 6 | 491 | 7 (7/0/0) | 6/7 | cross-address | PURE | 0 | Y | 0x801863cc modal | 3,437 |
-| 7 | 328 | 10 (10/0/0) | 10/10 | scattered | PURE | 1 | · | 0x801833f0 matched | 3,280 |
-| 8 | 770 | 4 (4/0/0) | 1/4 | per-location | PURE | 134 | · | 0x80144b9c matched-ov077 | 3,080 |
-| 9 | 611 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x80186e24 modal | 3,055 |
+| 7 | 770 | 4 (4/0/0) | 1/4 | per-location | PURE | 134 | · | 0x80144b9c matched-ov077 | 3,080 |
+| 8 | 611 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x80186e24 modal | 3,055 |
+| 9 | 328 | 9 (9/0/0) | 9/9 | scattered | PURE | 2 | · | 0x801833f0 matched | 2,952 |
| 10 | 557 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x80186570 modal | 2,785 |
| 11 | 551 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x80189540 modal | 2,755 |
| 12 | 125 | 22 (22/0/0) | 22/22 | scattered | PURE | 0 | Y | 0x80185440 modal | 2,750 |
-| 13 | 263 | 10 (10/0/0) | 10/10 | scattered | PURE | 1 | · | 0x80182fd4 matched | 2,630 |
-| 14 | 513 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x801878e8 modal | 2,565 |
-| 15 | 296 | 7 (7/0/0) | 7/7 | cross-address | PURE | 0 | · | 0x8017e2ec modal | 2,072 |
-| 16 | 137 | 15 (15/0/0) | 15/15 | scattered | PURE | 0 | Y | 0x80183084 modal | 2,055 |
-| 17 | 438 | 4 (4/0/0) | 1/4 | per-location | PURE | 134 | Y | 0x801380e0 matched-ov077 | 1,752 |
-| 18 | 579 | 3 (3/0/0) | 2/3 | cross-address | PURE | 0 | Y | 0x8018103c draft-ov077 | 1,737 |
-| 19 | 133 | 13 (13/0/0) | 10/13 | scattered | PURE | 1 | · | 0x8017d0bc matched | 1,729 |
-| 20 | 288 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80184c74 modal | 1,728 |
-| 21 | 281 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80186270 modal | 1,686 |
-| 22 | 240 | 7 (7/0/0) | 6/7 | cross-address | PURE | 0 | Y | 0x801872b4 modal | 1,680 |
-| 23 | 265 | 6 (0/6/0) | 6/6 | cross-address | IMM | 1 | · | 0x80183e04 matched | 1,590 |
-| 24 | 143 | 11 (11/0/0) | 10/11 | scattered | PURE | 1 | · | 0x8017d77c matched | 1,573 |
-| 25 | 251 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80186994 modal | 1,506 |
-| 26 | 710 | 2 (2/0/0) | 2/2 | cross-address | PURE | 1 | Y | 0x80191c50 matched | 1,420 |
-| 27 | 470 | 3 (3/0/0) | 3/3 | cross-address | PURE | 0 | Y | 0x80191320 modal | 1,410 |
-| 28 | 279 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x8017f2d4 modal | 1,395 |
-| 29 | 229 | 6 (6/0/0) | 2/6 | cross-address | PURE | 1 | · | 0x8017c290 matched | 1,374 |
-| 30 | 673 | 2 (2/0/0) | 2/2 | cross-address | PURE | 1 | Y | 0x8019059c matched | 1,346 |
-| 31 | 254 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x80188e1c modal | 1,270 |
-| 32 | 198 | 6 (6/0/0) | 6/6 | cross-address | PURE | 1 | · | 0x80181ee0 matched | 1,188 |
-| 33 | 198 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80185f58 modal | 1,188 |
-| 34 | 385 | 3 (3/0/0) | 3/3 | cross-address | PURE | 0 | Y | 0x8018ff98 modal | 1,155 |
-| 35 | 185 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80187aec modal | 1,110 |
-| 36 | 184 | 6 (6/0/0) | 2/6 | cross-address | PURE | 1 | · | 0x8017d318 matched | 1,104 |
-| 37 | 203 | 5 (0/5/0) | 4/5 | cross-address | IMM | 5 | · | 0x8017e804 matched | 1,015 |
-| 38 | 324 | 3 (3/0/0) | 2/3 | cross-address | PURE | 0 | Y | 0x80183324 draft-ov077 | 972 |
-| 39 | 121 | 8 (8/0/0) | 8/8 | cross-address | PURE | 9 | · | 0x8018b76c matched | 968 |
-| 40 | 95 | 10 (10/0/0) | 9/10 | scattered | PURE | 0 | Y | 0x80185d70 modal | 950 |
-| 41 | 231 | 4 (4/0/0) | 4/4 | cross-address | PURE | 0 | Y | 0x8017f83c modal | 924 |
-| 42 | 184 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x8017e3dc modal | 920 |
-| 43 | 115 | 8 (8/0/0) | 6/8 | cross-address | PURE | 0 | · | 0x8018089c modal | 920 |
-| 44 | 153 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x80181d94 modal | 918 |
-| 45 | 152 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x8018200c modal | 912 |
-| 46 | 180 | 5 (5/0/0) | 5/5 | cross-address | PURE | 0 | · | 0x80182a78 modal | 900 |
-| 47 | 225 | 4 (4/0/0) | 4/4 | cross-address | PURE | 0 | · | 0x801803e0 modal | 900 |
-| 48 | 150 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x8018829c modal | 900 |
-| 49 | 175 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x8017e6bc modal | 875 |
-| 50 | 124 | 7 (7/0/0) | 7/7 | cross-address | PURE | 0 | · | 0x80181cf0 modal | 868 |
+| 13 | 513 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x801878e8 modal | 2,565 |
+| 14 | 263 | 9 (9/0/0) | 9/9 | scattered | PURE | 2 | · | 0x80182fd4 matched | 2,367 |
+| 15 | 137 | 15 (15/0/0) | 15/15 | scattered | PURE | 0 | Y | 0x80183084 modal | 2,055 |
+| 16 | 438 | 4 (4/0/0) | 1/4 | per-location | PURE | 134 | Y | 0x801380e0 matched-ov077 | 1,752 |
+| 17 | 579 | 3 (3/0/0) | 2/3 | cross-address | PURE | 0 | Y | 0x8018103c draft-ov077 | 1,737 |
+| 18 | 288 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80184c74 modal | 1,728 |
+| 19 | 281 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80186270 modal | 1,686 |
+| 20 | 240 | 7 (7/0/0) | 6/7 | cross-address | PURE | 0 | Y | 0x801872b4 modal | 1,680 |
+| 21 | 251 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80186994 modal | 1,506 |
+| 22 | 143 | 10 (10/0/0) | 9/10 | scattered | PURE | 2 | · | 0x8017df78 matched | 1,430 |
+| 23 | 710 | 2 (2/0/0) | 2/2 | cross-address | PURE | 1 | Y | 0x80191c50 matched | 1,420 |
+| 24 | 470 | 3 (3/0/0) | 3/3 | cross-address | PURE | 0 | Y | 0x80191320 modal | 1,410 |
+| 25 | 279 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x8017f2d4 modal | 1,395 |
+| 26 | 673 | 2 (2/0/0) | 2/2 | cross-address | PURE | 1 | Y | 0x8019059c matched | 1,346 |
+| 27 | 265 | 5 (0/5/0) | 5/5 | cross-address | IMM | 2 | · | 0x80183e04 matched | 1,325 |
+| 28 | 254 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | Y | 0x80188e1c modal | 1,270 |
+| 29 | 198 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80185f58 modal | 1,188 |
+| 30 | 385 | 3 (3/0/0) | 3/3 | cross-address | PURE | 0 | Y | 0x8018ff98 modal | 1,155 |
+| 31 | 229 | 5 (5/0/0) | 1/5 | per-location | PURE | 2 | · | 0x8017e72c matched | 1,145 |
+| 32 | 185 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | Y | 0x80187aec modal | 1,110 |
+| 33 | 184 | 6 (6/0/0) | 2/6 | cross-address | PURE | 1 | · | 0x8017d318 matched | 1,104 |
+| 34 | 203 | 5 (0/5/0) | 4/5 | cross-address | IMM | 5 | · | 0x8017e804 matched | 1,015 |
+| 35 | 324 | 3 (3/0/0) | 2/3 | cross-address | PURE | 0 | Y | 0x80183324 draft-ov077 | 972 |
+| 36 | 121 | 8 (8/0/0) | 8/8 | cross-address | PURE | 9 | · | 0x8018b76c matched | 968 |
+| 37 | 95 | 10 (10/0/0) | 9/10 | scattered | PURE | 0 | Y | 0x80185d70 modal | 950 |
+| 38 | 231 | 4 (4/0/0) | 4/4 | cross-address | PURE | 0 | Y | 0x8017f83c modal | 924 |
+| 39 | 184 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x8017e3dc modal | 920 |
+| 40 | 115 | 8 (8/0/0) | 6/8 | cross-address | PURE | 0 | · | 0x8018089c modal | 920 |
+| 41 | 153 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x80181d94 modal | 918 |
+| 42 | 152 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x8018200c modal | 912 |
+| 43 | 180 | 5 (5/0/0) | 5/5 | cross-address | PURE | 0 | · | 0x80182a78 modal | 900 |
+| 44 | 225 | 4 (4/0/0) | 4/4 | cross-address | PURE | 0 | · | 0x801803e0 modal | 900 |
+| 45 | 150 | 6 (6/0/0) | 6/6 | cross-address | PURE | 0 | · | 0x8018829c modal | 900 |
+| 46 | 175 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x8017e6bc modal | 875 |
+| 47 | 124 | 7 (7/0/0) | 7/7 | cross-address | PURE | 0 | · | 0x80181cf0 modal | 868 |
+| 48 | 173 | 5 (5/0/0) | 4/5 | cross-address | PURE | 0 | · | 0x8017dc48 modal | 865 |
+| 49 | 214 | 4 (4/0/0) | 4/4 | cross-address | PURE | 0 | · | 0x8017f2e8 modal | 856 |
+| 50 | 122 | 7 (7/0/0) | 7/7 | cross-address | PURE | 0 | · | 0x8017f100 modal | 854 |
diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md
index 9a0a368cf..aa07c2f57 100644
--- a/docs/matching-cookbook.md
+++ b/docs/matching-cookbook.md
@@ -9533,6 +9533,25 @@ on **`tools/treelock.sh --status`**, which is a statement of intent spanning the
wrap a campaign in `nohup … &` inside a backgrounded call: the harness then signals completion of the
*wrapper* — a fleet check "finished" at 63/140.
+### STEP 0 of sibling-first: grep `src/` for a distinctive LITERAL from the `.s`
+
+§136c's search order (engine_core.h near-twin -> same-TU banked sibling -> the `.s`) has a hole: both
+of its first two steps are **same-TU or shared-header** scoped, so neither can reach a banked twin
+that lives in a **different overlay's** TU — and the large template classes live cross-overlay by
+construction. Measured: `func_80188C04` (328 ins) was byte-identical to an already-banked
+`func_801833F0` in `ov_SC02_028`, and one command found it —
+
+ grep -rn "E100000A" src/ # a magic word lifted straight out of the target .s
+
+— after which the body was reused verbatim with only the file-local type/macro suffixes renamed.
+**Put this ahead of engine_core.h.** Pick a distinctive constant from the target: a magic word, an
+unusual mask, an odd immediate. Corollary for the family map: it carries an in-family `exemplar`
+pointer only, so a family whose twin is banked *elsewhere* looks un-cracked — and, separately, that
+pointer can name an instance that is **already banked**, which hides the whole family from any
+ranking built on it. **Derive open sites from `corpus.stubs` over the member list.** Measured on one
+wave: ranking off the map's `exemplar` yielded 16,696 templatable ins; deriving from `corpus.stubs`
+yielded **41,023** — including a 55-ins family open in 138 overlays and a 46-ins one open in 133.
+
### Reconciling a gate-refused draft: which way you edit depends on WHERE the TU's decl is
A draft that `match_one`-MATCHes but the whole-binary gate refuses is declaration plumbing (the
diff --git a/docs/progress.fleet.md b/docs/progress.fleet.md
index e88fd8e70..1d28cc77d 100644
--- a/docs/progress.fleet.md
+++ b/docs/progress.fleet.md
@@ -4,23 +4,23 @@
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
# THREE progress metrics (all matter — see the labels):
-FLEET fn-count byte-ident: 340408 / 353721 = 96.24% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
-FLEET instr-weighted : 12344917 / 13141652 = 93.9% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number)
-FLEET distinct-code(uniq): 4978834 / 5634875 = 88.4% (77631/87459 unique fns; the DISTINCT-RE number)
+FLEET fn-count byte-ident: 340436 / 353721 = 96.24% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
+FLEET instr-weighted : 12350091 / 13141652 = 94.0% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number)
+FLEET distinct-code(uniq): 4983476 / 5634875 = 88.4% (77655/87459 unique fns; the DISTINCT-RE number)
MAIN game-code weighted : 436 / 60201 = 0.7% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-06-14; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift)
- (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12344481 / 13081451 = 94.4%)
+ (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12349655 / 13081451 = 94.4%)
-FLEET REAL substantive : 338553 (of which dedup-shared 241142 via 1910 groups / 241216 instances)
+FLEET REAL substantive : 338581 (of which dedup-shared 241142 via 1910 groups / 241216 instances)
FLEET LINKED PsyQ objs : 959
FLEET NON_MATCHING : 7 (0 in any default build — G4)
-FLEET INCLUDE_ASM stubs : 13306
+FLEET INCLUDE_ASM stubs : 13278
FLEET matchable : 353721
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
|---|---:|---:|---:|---:|---:|---:|
| main | 54 | 2 | 959 | 1055 | 2096 | 50.3% |
| resident | 129 | 0 | 0 | 131 | 145 | 90.3% |
-| ov_SC01_000 | 2382 | 1753 | 0 | 2382 | 2403 | 99.1% |
+| ov_SC01_000 | 2384 | 1753 | 0 | 2384 | 2403 | 99.2% |
| ov_SC01_001 | 2390 | 1754 | 0 | 2392 | 2466 | 97.0% |
| ov_SC01_004 | 2384 | 1745 | 0 | 2385 | 2414 | 98.8% |
| ov_SC01_005 | 2414 | 1768 | 0 | 2414 | 2503 | 96.4% |
@@ -35,22 +35,22 @@ FLEET matchable : 353721
| ov_SC02_003 | 2507 | 1793 | 0 | 2507 | 2683 | 93.4% |
| ov_SC02_004 | 2382 | 1749 | 0 | 2382 | 2401 | 99.2% |
| ov_SC02_005 | 2530 | 1745 | 0 | 2540 | 2927 | 86.8% |
-| ov_SC02_011 | 2614 | 1752 | 0 | 2625 | 2893 | 90.7% |
+| ov_SC02_011 | 2616 | 1752 | 0 | 2627 | 2893 | 90.8% |
| ov_SC02_015 | 2393 | 1751 | 0 | 2393 | 2414 | 99.1% |
| ov_SC02_016 | 2474 | 1751 | 0 | 2477 | 2545 | 97.3% |
| ov_SC02_017 | 2542 | 1751 | 0 | 2550 | 2732 | 93.3% |
| ov_SC02_021 | 2398 | 1751 | 0 | 2398 | 2437 | 98.4% |
-| ov_SC02_026 | 2489 | 1749 | 0 | 2495 | 2572 | 97.0% |
+| ov_SC02_026 | 2490 | 1749 | 0 | 2496 | 2572 | 97.0% |
| ov_SC02_027 | 2546 | 1749 | 0 | 2555 | 2692 | 94.9% |
| ov_SC02_028 | 2552 | 1749 | 0 | 2562 | 2701 | 94.9% |
-| ov_SC02_031 | 2485 | 1750 | 0 | 2490 | 2562 | 97.2% |
+| ov_SC02_031 | 2486 | 1750 | 0 | 2491 | 2562 | 97.2% |
| ov_SC02_035 | 2473 | 1749 | 0 | 2476 | 2520 | 98.3% |
| ov_SC02_039 | 2387 | 1749 | 0 | 2387 | 2416 | 98.8% |
| ov_SC02_041 | 2464 | 1749 | 0 | 2467 | 2561 | 96.3% |
-| ov_SC03_001 | 2650 | 1750 | 0 | 2667 | 2869 | 93.0% |
+| ov_SC03_001 | 2651 | 1750 | 0 | 2668 | 2869 | 93.0% |
| ov_SC03_002 | 2526 | 1754 | 0 | 2541 | 2631 | 96.6% |
| ov_SC03_003 | 2391 | 1749 | 0 | 2392 | 2423 | 98.7% |
-| ov_SC03_006 | 2540 | 1755 | 0 | 2549 | 2767 | 92.1% |
+| ov_SC03_006 | 2541 | 1755 | 0 | 2550 | 2767 | 92.2% |
| ov_SC03_007 | 2454 | 1749 | 0 | 2458 | 2623 | 93.7% |
| ov_SC03_010 | 2407 | 1749 | 0 | 2407 | 2471 | 97.4% |
| ov_SC03_011 | 2409 | 1749 | 0 | 2415 | 2527 | 95.6% |
@@ -59,12 +59,12 @@ FLEET matchable : 353721
| ov_SC03_014 | 2563 | 1777 | 0 | 2563 | 2685 | 95.5% |
| ov_SC03_015 | 2562 | 1777 | 0 | 2562 | 2685 | 95.4% |
| ov_SC03_023 | 2393 | 1749 | 0 | 2394 | 2435 | 98.3% |
-| ov_SC03_024 | 2504 | 1754 | 0 | 2511 | 2641 | 95.1% |
-| ov_SC03_028 | 2451 | 1749 | 0 | 2455 | 2664 | 92.2% |
+| ov_SC03_024 | 2505 | 1754 | 0 | 2512 | 2641 | 95.1% |
+| ov_SC03_028 | 2452 | 1749 | 0 | 2456 | 2664 | 92.2% |
| ov_SC03_029 | 2493 | 1751 | 0 | 2503 | 2644 | 94.7% |
| ov_SC03_030 | 2411 | 1754 | 0 | 2413 | 2495 | 96.7% |
| ov_SC03_031 | 2440 | 1749 | 0 | 2443 | 2514 | 97.2% |
-| ov_SC03_089 | 2499 | 1754 | 0 | 2506 | 2581 | 97.1% |
+| ov_SC03_089 | 2501 | 1754 | 0 | 2508 | 2581 | 97.2% |
| ov_SC03_090 | 2509 | 1754 | 0 | 2517 | 2625 | 95.9% |
| ov_SC03_091 | 2523 | 1749 | 0 | 2531 | 2640 | 95.9% |
| ov_SC03_092 | 2492 | 1754 | 0 | 2504 | 2587 | 96.8% |
@@ -84,18 +84,18 @@ FLEET matchable : 353721
| ov_SC03_108 | 2390 | 1749 | 0 | 2390 | 2443 | 97.8% |
| ov_SC03_109 | 2400 | 1749 | 0 | 2402 | 2424 | 99.1% |
| ov_SC03_110 | 2432 | 1749 | 0 | 2432 | 2468 | 98.5% |
-| ov_SC03_111 | 2462 | 1749 | 0 | 2465 | 2510 | 98.2% |
+| ov_SC03_111 | 2463 | 1749 | 0 | 2466 | 2510 | 98.2% |
| ov_SC03_112 | 2424 | 1751 | 0 | 2426 | 2526 | 96.0% |
-| ov_SC03_113 | 2425 | 1751 | 0 | 2428 | 2468 | 98.4% |
-| ov_SC03_114 | 2382 | 1749 | 0 | 2384 | 2415 | 98.7% |
+| ov_SC03_113 | 2426 | 1751 | 0 | 2429 | 2468 | 98.4% |
+| ov_SC03_114 | 2383 | 1749 | 0 | 2385 | 2415 | 98.8% |
| ov_SC03_115 | 2423 | 1749 | 0 | 2425 | 2472 | 98.1% |
| ov_SC03_116 | 2390 | 1749 | 0 | 2393 | 2438 | 98.2% |
| ov_SC03_117 | 2458 | 1749 | 0 | 2464 | 2557 | 96.4% |
-| ov_SC03_118 | 2530 | 1773 | 0 | 2531 | 2685 | 94.3% |
-| ov_SC03_119 | 2526 | 1773 | 0 | 2527 | 2685 | 94.1% |
+| ov_SC03_118 | 2531 | 1773 | 0 | 2532 | 2685 | 94.3% |
+| ov_SC03_119 | 2527 | 1773 | 0 | 2528 | 2685 | 94.2% |
| ov_SC03_121 | 2396 | 1749 | 0 | 2399 | 2459 | 97.6% |
| ov_SC03_124 | 2560 | 1745 | 0 | 2580 | 2741 | 94.1% |
-| ov_SC03_125 | 2513 | 1749 | 0 | 2525 | 2588 | 97.6% |
+| ov_SC03_125 | 2514 | 1749 | 0 | 2526 | 2588 | 97.6% |
| ov_SC03_126 | 2392 | 1751 | 0 | 2392 | 2423 | 98.7% |
| ov_SC04_000 | 2465 | 1753 | 0 | 2474 | 2546 | 97.2% |
| ov_SC04_002 | 2492 | 1749 | 0 | 2496 | 2636 | 94.7% |
@@ -107,19 +107,19 @@ FLEET matchable : 353721
| ov_SC04_008 | 2393 | 1749 | 0 | 2393 | 2415 | 99.1% |
| ov_SC04_009 | 2419 | 1749 | 0 | 2422 | 2441 | 99.2% |
| ov_SC04_010 | 2395 | 1749 | 0 | 2396 | 2419 | 99.0% |
-| ov_SC04_011 | 2507 | 1754 | 0 | 2513 | 2803 | 89.7% |
+| ov_SC04_011 | 2508 | 1754 | 0 | 2514 | 2803 | 89.7% |
| ov_SC04_012 | 2390 | 1749 | 0 | 2391 | 2420 | 98.8% |
| ov_SC04_015 | 2518 | 1750 | 0 | 2529 | 2611 | 96.9% |
-| ov_SC04_016 | 2393 | 1749 | 0 | 2395 | 2440 | 98.2% |
+| ov_SC04_016 | 2394 | 1749 | 0 | 2396 | 2440 | 98.2% |
| ov_SC04_018 | 2662 | 1785 | 0 | 2662 | 2857 | 93.2% |
| ov_SC04_019 | 2654 | 1785 | 0 | 2654 | 2857 | 92.9% |
-| ov_SC04_020 | 2500 | 1749 | 0 | 2512 | 2567 | 97.9% |
+| ov_SC04_020 | 2501 | 1749 | 0 | 2513 | 2567 | 97.9% |
| ov_SC04_021 | 2392 | 1751 | 0 | 2392 | 2423 | 98.7% |
| ov_SC05_000 | 2399 | 1753 | 0 | 2402 | 2422 | 99.2% |
| ov_SC05_001 | 2467 | 1749 | 0 | 2472 | 2574 | 96.0% |
| ov_SC05_002 | 2423 | 1749 | 0 | 2426 | 2442 | 99.3% |
| ov_SC05_003 | 2404 | 1749 | 0 | 2405 | 2481 | 96.9% |
-| ov_SC05_004 | 2413 | 1749 | 0 | 2415 | 2464 | 98.0% |
+| ov_SC05_004 | 2414 | 1749 | 0 | 2416 | 2464 | 98.1% |
| ov_SC05_005 | 2429 | 1754 | 0 | 2430 | 2491 | 97.6% |
| ov_SC05_006 | 2415 | 1749 | 0 | 2415 | 2430 | 99.4% |
| ov_SC05_007 | 2422 | 1749 | 0 | 2427 | 2482 | 97.8% |
@@ -128,18 +128,18 @@ FLEET matchable : 353721
| ov_SC05_010 | 2439 | 1749 | 0 | 2443 | 2588 | 94.4% |
| ov_SC05_011 | 2389 | 1749 | 0 | 2390 | 2409 | 99.2% |
| ov_SC05_017 | 2633 | 1746 | 0 | 2644 | 2842 | 93.0% |
-| ov_SC05_018 | 2529 | 1749 | 0 | 2542 | 2673 | 95.1% |
+| ov_SC05_018 | 2530 | 1749 | 0 | 2543 | 2673 | 95.1% |
| ov_SC05_019 | 2392 | 1751 | 0 | 2392 | 2423 | 98.7% |
-| ov_SC06_000 | 2518 | 1758 | 0 | 2521 | 2691 | 93.7% |
-| ov_SC06_006 | 2415 | 1749 | 0 | 2416 | 2511 | 96.2% |
+| ov_SC06_000 | 2519 | 1758 | 0 | 2522 | 2691 | 93.7% |
+| ov_SC06_006 | 2416 | 1749 | 0 | 2417 | 2511 | 96.3% |
| ov_SC06_008 | 2472 | 1751 | 0 | 2478 | 2542 | 97.5% |
| ov_SC06_010 | 2446 | 1749 | 0 | 2451 | 2517 | 97.4% |
-| ov_SC06_011 | 2407 | 1749 | 0 | 2411 | 2468 | 97.7% |
+| ov_SC06_011 | 2408 | 1749 | 0 | 2412 | 2468 | 97.7% |
| ov_SC06_013 | 2397 | 1749 | 0 | 2398 | 2425 | 98.9% |
| ov_SC06_014 | 2408 | 1749 | 0 | 2410 | 2453 | 98.2% |
| ov_SC06_015 | 2402 | 1749 | 0 | 2402 | 2421 | 99.2% |
| ov_SC06_016 | 2444 | 1749 | 0 | 2446 | 2549 | 96.0% |
-| ov_SC06_018 | 2476 | 1751 | 0 | 2483 | 2665 | 93.2% |
+| ov_SC06_018 | 2477 | 1751 | 0 | 2484 | 2665 | 93.2% |
| ov_SC06_020 | 2432 | 1751 | 0 | 2433 | 2518 | 96.6% |
| ov_SC06_022 | 2462 | 1749 | 0 | 2470 | 2642 | 93.5% |
| ov_SC06_024 | 2481 | 1749 | 0 | 2487 | 2667 | 93.3% |
@@ -147,7 +147,7 @@ FLEET matchable : 353721
| ov_SC06_027 | 2384 | 1749 | 0 | 2385 | 2408 | 99.0% |
| ov_SC06_029 | 2466 | 1749 | 0 | 2478 | 2662 | 93.1% |
| ov_SC06_030 | 2405 | 1749 | 0 | 2405 | 2456 | 97.9% |
-| ov_SC06_032 | 2468 | 1750 | 0 | 2475 | 2658 | 93.1% |
+| ov_SC06_032 | 2469 | 1750 | 0 | 2476 | 2658 | 93.2% |
| ov_SC06_033 | 2467 | 1750 | 0 | 2474 | 2631 | 94.0% |
| ov_SC07_000 | 2425 | 1753 | 0 | 2427 | 2521 | 96.3% |
| ov_SC07_001 | 2397 | 1749 | 0 | 2399 | 2454 | 97.8% |
diff --git a/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c b/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c
index c7ed774f1..d7582d1dd 100644
--- a/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c
+++ b/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c
@@ -2243,7 +2243,30 @@ void func_80131FDC(void *a0) {
}
-INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8012ACE0", func_80132018);
+extern void func_8012C1B8(void);
+extern void func_8012CAE4(void *a0);
+extern void func_8001C214(int, int);
+extern void (*D_8017F130[])(void);
+extern s32 D_8017F134[];
+
+void func_80132018(void *a0)
+{
+ s32 v0;
+
+ v0 = ((int (*)(void))func_8012C1B8)();
+ *(s32 *)((s32)a0 + 0x20) = v0;
+ if (v0 == 0) {
+ func_8012CAE4(a0);
+ } else {
+ func_8001C214(v0, 0);
+ *(s16 *)((s32)a0 + 0x5c) = 0x80;
+ *(u16 *)((s32)a0 + 0x2) += 1;
+ *(s32 *)((s32)a0 + 0x58) = (s32)&D_8017F134[(*(u16 *)((s32)a0 + 0x70) & 0xfff) * 5];
+ *(s32 *)((s32)a0 + 0xdc) = (s32)D_8017F130[(*(u16 *)((s32)a0 + 0x70) & 0xfff) * 5];
+ *(u16 *)((s32)a0 + 0xfc) = (*(u16 *)((s32)a0 + 0x70) >> 0xc) << 9;
+ }
+}
+
DEFINE_func_801320D0() /* dedup: shared engine-core @0x801320D0 (src/shared) */
diff --git a/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c b/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c
index 398e90288..5462d8218 100644
--- a/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c
+++ b/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c
@@ -2945,7 +2945,48 @@ s32 func_80175820(void)
}
-INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_801734BC", func_801758FC);
+/* func_801758FC — twin of the byte-matched func_80175820 / func_801759D8 in this same TU.
+ * Same three-part body (part1: mask-merge a word at ptr[N] with a masked read from
+ * D_8011F7A8+idx*4+B; part2: mask-merge *p2 (p2 = D_8011F7A8+idx*4+A) with the old ptr[N] value;
+ * part3: D_800AF634[idx].g0 accumulates ((D_8011F7A8+idx*4+B) - ((D_8011F7A8+idx*4+A) - 0x14)) >> 2),
+ * here with N=3 (offset 0xC), A=0x28 (D_8011F7D0), B=0x30 (D_8011F7D8).
+ * The two __asm__ memory fences keep the three parts from CSE-ing their base addresses together,
+ * matching func_80175820 / func_801759D8 exactly (same idiom, different slot/offsets).
+ */
+
+typedef struct { u32 *f0; s32 pad[4]; } S_AE7BC_801758FC; /* size 0x14 */
+typedef struct { s32 g0; s32 pad[2]; } S_AF634_801758FC; /* size 0x0C */
+
+s32 func_801758FC(void)
+{
+ extern s16 D_800B9A02;
+ extern S_AE7BC_801758FC D_800AE7BC[];
+ extern S_AF634_801758FC D_800AF634[];
+ extern u8 D_8011F7A8;
+ u8 *p = (u8 *)&D_8011F7A8;
+ u16 *q;
+ u32 *ptr;
+ u32 old;
+ u32 *p2;
+
+ q = (u16 *)&(*(u16 *)&D_800B9A02);
+
+ ptr = D_800AE7BC[*q].f0;
+ old = ptr[3];
+ ptr[3] = (old & 0xff000000) | (*(u32 *)(p + *q * 4 + 0x30) & 0xffffff);
+ __asm__("" ::: "memory");
+
+ p2 = *(u32 **)(p + *q * 4 + 0x28);
+ *p2 = (*p2 & 0xff000000) | (old & 0xffffff);
+ __asm__("" ::: "memory");
+
+ {
+ s32 acc = D_800AF634[*q].g0;
+ s32 t = *(s32 *)(p + *q * 4 + 0x28) - 0x14;
+ D_800AF634[*q].g0 = acc + ((*(s32 *)(p + *q * 4 + 0x30) - t) >> 2);
+ }
+}
+
diff --git a/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c b/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c
index b2ee84f1d..aeac6fbd2 100644
--- a/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c
+++ b/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c
@@ -4824,7 +4824,79 @@ void func_8017DD34(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017DE10);
+/* func_8017DE10 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10;
+
+void func_8017DE10(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
@@ -5097,7 +5169,142 @@ void func_8017E5E8(void) {
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017E5F0);
-INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017E72C);
+/* func_8017E72C -- ov_SC02_011, TU ov_SC02_011_jr_8017AE2C.c
+ *
+ * §136c sibling-first: near-twin is the already-banked func_8017C290 in
+ * src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c (same "jr_8017AE2C" family).
+ * Reused verbatim from it: the MATRIX/SVECTOR/PW (packed align-1, 4 byte)
+ * type trio, the gte_ldv0/gte_rt/gte_stsv inline-asm macros, the whole
+ * statement shape and order, and the extern decls for func_80013F3C /
+ * RotMatrixZ / func_8004914C / func_800491AC / func_80017714 / rand.
+ * Only the data symbols differ (D_801EB4C8 in place of D_801EA8C0, etc.) --
+ * none of them appear anywhere else in this TU, so fresh local types are
+ * declared here under a _8017E72C suffix.
+ */
+
+typedef struct { s16 m[3][3]; s16 pad; s32 t[3]; } MATRIX_8017E72C;
+typedef struct { u16 vx, vy, vz, pad; } SVECTOR_8017E72C;
+struct PW8017E72C { int w; } __attribute__((packed, aligned(1)));
+
+extern void func_80013F3C(s32 a0);
+extern void RotMatrixZ(s32, void *);
+extern void func_8004914C(void *a0);
+extern void func_800491AC(void *a0);
+extern int rand(void);
+extern void func_80017714(void *);
+
+extern SVECTOR_8017E72C D_801EB4C8[4];
+extern struct PW8017E72C D_801EB4E8;
+extern struct PW8017E72C D_801EB4EC;
+extern u8 D_801EB4F0, D_801EB4F1, D_801EB4F2, D_801EB4F4, D_801EB4F5, D_801EB4F6;
+extern int D_801EB4F8;
+extern struct PW8017E72C D_80194BA4[];
+
+#define gte_ldv0(r0) __asm__ __volatile__( \
+ "lwc2 $0, 0(%0)\n" \
+ "lwc2 $1, 4(%0)\n" \
+ : : "r"(r0) : "memory")
+
+#define gte_rt() __asm__ __volatile__( \
+ "nop\n" \
+ "nop\n" \
+ "mvmva 1, 0, 0, 0, 0\n" \
+ : : : "memory")
+
+#define gte_stsv(r0) __asm__ __volatile__( \
+ "mfc2 $12, $9\n" \
+ "mfc2 $13, $10\n" \
+ "mfc2 $14, $11\n" \
+ "sh $12, 0(%0)\n" \
+ "sh $13, 2(%0)\n" \
+ "sh $14, 4(%0)\n" \
+ : : "r"(r0) : "$12", "$13", "$14", "memory")
+
+void func_8017E72C(int a, s16 *b, SVECTOR_8017E72C *c, SVECTOR_8017E72C *d,
+ SVECTOR_8017E72C *e, SVECTOR_8017E72C *f, s16 *g)
+{
+ MATRIX_8017E72C m;
+ SVECTOR_8017E72C *r0_00;
+ SVECTOR_8017E72C *pSVar6;
+ SVECTOR_8017E72C *r0;
+ int r;
+ int mask;
+
+ func_80013F3C((s32)&m);
+ RotMatrixZ(g[0], &m);
+ m.t[0] = b[0];
+ m.t[1] = b[1];
+ m.t[2] = 0;
+ func_8004914C(&m);
+ func_800491AC(&m);
+
+ r0_00 = &D_801EB4C8[0];
+ if (*(s16 *)(a + 0x12) == 0) {
+ D_801EB4F8 = 0x50000000;
+ D_801EB4E8 = D_80194BA4[*(s32 *)(a + 0x2C)];
+ D_801EB4EC = D_80194BA4[*(s32 *)(a + 0x2C)];
+ D_801EB4F0 = 0;
+ D_801EB4F1 = 0;
+ D_801EB4F2 = 0;
+ D_801EB4F4 = 0;
+ D_801EB4F5 = 0;
+ D_801EB4F6 = 0;
+ }
+
+ f->vx = f->vx + c->vx;
+ f->vy = f->vy + c->vy;
+ r = rand();
+ mask = f->pad & r;
+ if (*(u16 *)(a + 0x12) & 1)
+ f->vx = f->vx + mask;
+ else
+ f->vx = f->vx - mask;
+ r = rand();
+ { int t = f->vy - 0x10; f->vy = t + (r & 0x1f); }
+
+ gte_ldv0(c);
+ gte_rt();
+ gte_stsv(r0_00);
+
+ gte_ldv0(f);
+ gte_rt();
+ gte_stsv(r0_00 + 1);
+
+ gte_ldv0(d);
+ gte_rt();
+ r0 = r0_00 + 2;
+ gte_stsv(r0);
+
+ *d = *f;
+ r = rand();
+ d->vx = d->vx - (f->pad & r);
+
+ gte_ldv0(d);
+ gte_rt();
+ pSVar6 = r0_00 + 3;
+ gte_stsv(pSVar6);
+
+ r0_00->vz = ((u16 *)b)[2];
+ func_80017714(r0_00);
+
+ gte_ldv0(e);
+ gte_rt();
+ gte_stsv(r0);
+
+ *e = *f;
+ r = rand();
+ e->vx = e->vx + (f->pad & r);
+
+ gte_ldv0(e);
+ gte_rt();
+ gte_stsv(pSVar6);
+
+ r0_00->vz = ((u16 *)b)[2];
+ func_80017714(r0_00);
+
+ *c = *f;
+}
+
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017EAC0);
diff --git a/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c b/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c
index 9c687a1ab..3fadc1626 100644
--- a/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c
+++ b/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c
@@ -6542,7 +6542,27 @@ void func_80185634(void *a0) {
}
-INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_801856E4);
+#include "common.h"
+
+/* §37 data asm-label alias: D_800A5EA8/D_800A5EB0/struct B16_80185634 are already declared
+ * above the splice point (func_80185634's block, same TU). Redeclaring the struct TAG body
+ * verbatim would be a C89 duplicate-definition error there, so alias a private identifier
+ * onto the same linker symbol -- zero blast radius, identical %hi/%lo(D_800A5EA8) codegen. */
+struct B16_801856E4 { s32 w[4]; };
+
+extern struct B16_801856E4 aD800A5EA8 __asm__("D_800A5EA8");
+extern struct B16_801856E4 D_801CCC30;
+extern s32 D_800A5EB0;
+extern s32 func_8004787C(s32 a0);
+extern void func_80028620(s32 a0, void *a1);
+
+void func_801856E4(void *a0) {
+ aD800A5EA8 = D_801CCC30;
+ D_800A5EB0 = func_8004787C(*(s16 *)((s32)a0 + 0xFE)) * 6 / 4096 - 3;
+ *(u16 *)((s32)a0 + 0xFE) = (*(u16 *)((s32)a0 + 0xFE) + 0x71) & 0xFFF;
+ func_80028620(2, &aD800A5EA8);
+}
+
#include "common.h"
diff --git a/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c b/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c
index 6026f16fc..36a8b8e12 100644
--- a/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c
+++ b/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c
@@ -5457,7 +5457,81 @@ void func_8017ED60(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_8017AE2C", func_8017EE3C);
+
+
+/* func_8017EE3C -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017EE3C;
+
+void func_8017EE3C(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017EE3C D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017EE3C m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c b/src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c
index 0c43f3cac..16b6c60b2 100644
--- a/src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c
+++ b/src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c
@@ -4275,7 +4275,101 @@ void func_8017DEE8(void *arg0) {
}
-INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_jr_8017AE2C", func_8017DF78);
+
+
+extern u8 D_80078EB1;
+extern u8 D_80078E78[];
+extern u8 D_800AF630[];
+extern Ent_8017D6EC_8017DEE8 D_801EE888[];
+extern s32 func_8004787C(s32 a0);
+extern void func_8012AD44(s32 *a0, s16 a1);
+extern void func_8017E1B4(void *a0);
+extern void func_8017E2C0(void *arg0);
+
+void func_8017DF78(void *arg0)
+{
+ u8 *m;
+ u8 *e78;
+ s32 k;
+
+ m = D_800AF630;
+ e78 = D_80078E78;
+
+ if (D_80078EB1 >= 9) {
+ s32 count;
+ s32 i;
+ u8 *base;
+
+ base = (u8 *)D_801EE888;
+ count = 0;
+ for (i = 0; i < 4; i++) {
+ if (*(s32 *)(base + i * 0x24 + 0x1C) == 0) {
+ count++;
+ }
+ }
+ if (count == 0) {
+ func_8012AD44((s32 *)arg0, 0);
+ return;
+ }
+ }
+
+ for (k = 0; k < 4; k++) {
+ u8 *p = (u8 *)D_801EE888 + k * 0x24;
+ s32 c;
+
+ if (*(s32 *)(p + 0x1C) != 0) {
+ continue;
+ }
+
+ {
+ s16 val = *(s16 *)(p + 0xC);
+ if (val < 0x401) {
+ *(s16 *)(p + 0xC) = val + 0xB;
+ } else if (*(s32 *)(p + 0x18) != 0) {
+ *(s32 *)(p + 0x18) -= 1;
+ } else {
+ *(s16 *)(p + 0xC) = val + 0xB;
+ }
+ }
+
+ if (*(s16 *)(p + 0xC) >= 0x801) {
+ *(s16 *)(p + 0xC) = 0;
+ }
+
+ c = (func_8004787C(*(s16 *)(p + 0xC)) / 64) & 0xFF;
+ c = c | (c << 16 | c << 8);
+ *(s32 *)(p + 0x4) = c;
+
+ c = (func_8004787C(*(s16 *)(p + 0xC)) / 256) & 0xFF;
+ c = c | (c << 16 | c << 8);
+ *(s32 *)(p + 0x8) = c;
+
+ if ((*(u16 *)(m + 0xA3AA) & 1) == 0) {
+ s16 cnt = *(u16 *)(p + 0xE) + 1;
+ *(u16 *)(p + 0xE) = cnt;
+ if (cnt >= 0x40) {
+ *(u16 *)(p + 0xE) = 0;
+ }
+ }
+
+ {
+ s32 val2 = *(s16 *)(p + 0xC);
+ if (val2 == 0) {
+ *(s32 *)(p + 0x1C) = 1;
+ } else if (val2 >= 0x556) {
+ if (*(s32 *)(p + 0x20) == 0) {
+ *(s32 *)(p + 0x20) = 1;
+ if (e78[0x39] < 9) {
+ func_8017E1B4(p);
+ }
+ }
+ }
+ }
+
+ func_8017E2C0(p);
+ }
+}
+
INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_jr_8017AE2C", func_8017E1B4);
diff --git a/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c b/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c
index 24e79ec1c..2e7ea688e 100644
--- a/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c
+++ b/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c
@@ -5249,7 +5249,81 @@ void func_8017E634(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_8017AE2C", func_8017E710);
+
+
+/* func_8017E710 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017E710;
+
+void func_8017E710(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017E710 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017E710 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c b/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c
index 960ac12f5..274109cd9 100644
--- a/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c
+++ b/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c
@@ -3855,7 +3855,81 @@ void func_8017FAEC(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_8017FBC8);
+
+
+/* func_8017FBC8 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017FBC8;
+
+void func_8017FBC8(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017FBC8 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017FBC8 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_028/ov_SC03_028_jr_8017AE2C.c b/src/ov_SC03_028/ov_SC03_028_jr_8017AE2C.c
index 665f424fb..214b016f8 100644
--- a/src/ov_SC03_028/ov_SC03_028_jr_8017AE2C.c
+++ b/src/ov_SC03_028/ov_SC03_028_jr_8017AE2C.c
@@ -4341,7 +4341,81 @@ void func_8017D294(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028_jr_8017AE2C", func_8017D370);
+
+
+/* func_8017D370 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017D370;
+
+void func_8017D370(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017D370 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017D370 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c b/src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c
index 576a6764e..af5824cc5 100644
--- a/src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c
+++ b/src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c
@@ -7477,9 +7477,383 @@ INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017CA80", func_801886B
INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017CA80", func_8018879C);
-INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017CA80", func_801887E8);
+#include "common.h"
+
+/* func_801887E8 -- ov_SC03_089, TU src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c
+ *
+ * This is the SAME routine (family of 10) as the already-BANKED
+ * func_80182FD4 in src/ov_SC02_028/ov_SC02_028_jr_8017D898.c -- identical
+ * shape confirmed instruction-for-instruction against the target .s:
+ * - offset 0x20: source point-offset table pointer (Src->pt[12], stride 4,
+ * u16 vx,vy each, table starts at +0x10 within the struct)
+ * - offset 0x2E/0x30/0x32: base position (u16 vx,vy,vz)
+ * - offset 0x34: dispatch func_8001E094()/func_8001E378(a0)
+ * - single-point gte_ldv0/rtps/stsxy(&buf[0]) + gte_stflg + gte_stszotz
+ * - flag & ~0x1000 early-out
+ * - offset 0x2C: w; z = otz+1, adjusted by (w&0xC000) 0x4000/0x8000/0xC000
+ * cases, clamped >=0, early-out if z>=0x1000
+ * - offset 0x1E bit 0x8000: two different traversal orders over pt[],
+ * both ending in a call taking (a0, a1, &buf[0], ot [+z]).
+ * Only the callee at the very end differs (func_80188C04 here vs
+ * func_801833F0 there) and the per-overlay local type names.
+ */
+
+void func_801887E8(void *a0, void *a1)
+{
+ typedef struct { u16 vx, vy; } Pt2_801887E8;
+ typedef struct { u8 pad[0x10]; Pt2_801887E8 pt[12]; } Src_801887E8;
+ typedef struct { u16 vx, vy, vz, pad; } Vec8_801887E8;
+
+ extern void func_8001E094(void);
+ extern void func_8001E378(void *a0);
+ extern void func_80188C04(void *a0, void *a1, u32 *a2, u32 *a3);
+ extern u8 D_800A6610[];
+ extern short D_800B9A02;
+
+ Vec8_801887E8 base;
+ Vec8_801887E8 v[3];
+ u32 buf[19];
+ long flag;
+ long otz;
+ long flag2;
+
+ Src_801887E8 *s;
+ u32 *ot;
+ s32 z;
+ s32 i;
+ u16 w;
+
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_ldv3(r0, r1, r2) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 );" \
+ "lwc2 $2, 0( %1 );" \
+ "lwc2 $3, 4( %1 );" \
+ "lwc2 $4, 0( %2 );" \
+ "lwc2 $5, 4( %2 )" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) )
+
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_rtpt() __asm__ volatile ("nop;nop;rtpt")
+
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy3(r0, r1, r2) __asm__ volatile ( \
+ "swc2 $12, 0( %0 );" \
+ "swc2 $13, 0( %1 );" \
+ "swc2 $14, 0( %2 )" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) \
+ : "memory" )
+
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+
+ ot = (u32 *)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ s = *(Src_801887E8 **)((s32)a0 + 0x20);
+ if (s == 0) {
+ return;
+ }
+
+ if (*(s32 *)((s32)a0 + 0x34) != 0) {
+ func_8001E094();
+ } else {
+ func_8001E378(a0);
+ }
+
+ base.vx = *(u16 *)((s32)a0 + 0x2E);
+ base.vy = *(u16 *)((s32)a0 + 0x30);
+ base.vz = *(u16 *)((s32)a0 + 0x32);
+
+ gte_ldv0(&base);
+ gte_rtps();
+ gte_stsxy(&buf[0]);
+ gte_stflg(&flag);
+ gte_stszotz(&otz);
+
+ if (flag & ~0x1000) {
+ return;
+ }
+
+ w = *(u16 *)((s32)a0 + 0x2C);
+ z = otz + 1;
+ if ((w & 0xC000) != 0) {
+ if ((w & 0xC000) == 0xC000) {
+ z -= (w & 0xFFF);
+ if (z < 0) {
+ z = 0;
+ }
+ } else {
+ z += (w & 0xFFF);
+ }
+ }
+ if (z >= 0x1000) {
+ return;
+ }
+
+ if (*(s16 *)((s32)a0 + 0x1E) & 0x8000) {
+ for (i = 0; i < 12; i += 6) {
+ v[0].vx = base.vx + s->pt[i].vx;
+ v[0].vy = base.vy + s->pt[i].vy;
+ v[0].vz = base.vz;
+ v[1].vx = base.vx + s->pt[i + 2].vx;
+ v[1].vy = base.vy + s->pt[i + 2].vy;
+ v[1].vz = base.vz;
+ v[2].vx = base.vx + s->pt[i + 4].vx;
+ v[2].vy = base.vy + s->pt[i + 4].vy;
+ v[2].vz = base.vz;
+ gte_ldv3(&v[0], &v[1], &v[2]);
+ gte_rtpt();
+ gte_stsxy3(&buf[i + 1], &buf[i + 3], &buf[i + 5]);
+ }
+ for (i = 1; i < 12; i += 2) {
+ v[0].vx = base.vx + s->pt[i].vx;
+ v[0].vy = base.vy + s->pt[i].vy;
+ v[0].vz = base.vz;
+ gte_ldv0(&v[0]);
+ gte_rtps();
+ gte_stsxy(&buf[i + 1]);
+ gte_stflg(&flag2);
+ gte_stszotz(&otz);
+ buf[13 + (i >> 1)] = otz + 1;
+ }
+ func_80188C04(a0, a1, &buf[0], ot);
+ } else {
+ for (i = 0; i < 12; i += 3) {
+ v[0].vx = base.vx + s->pt[i].vx;
+ v[0].vy = base.vy + s->pt[i].vy;
+ v[0].vz = base.vz;
+ v[1].vx = base.vx + s->pt[i + 1].vx;
+ v[1].vy = base.vy + s->pt[i + 1].vy;
+ v[1].vz = base.vz;
+ v[2].vx = base.vx + s->pt[i + 2].vx;
+ v[2].vy = base.vy + s->pt[i + 2].vy;
+ v[2].vz = base.vz;
+ gte_ldv3(&v[0], &v[1], &v[2]);
+ gte_rtpt();
+ gte_stsxy3(&buf[i + 1], &buf[i + 2], &buf[i + 3]);
+ }
+ func_80188C04(a0, a1, &buf[0], ot + z);
+ }
+}
+
+
+/* func_80188C04 - ov_SC03_089 (328 ins, frame 0x38, leaf, 10-member family).
+ *
+ * §136c SIBLING-FIRST: this is a BYTE-IDENTICAL clone of the already-banked
+ * func_801833F0 in src/ov_SC02_028/ov_SC02_028_jr_8017D898.c:4441.
+ * diff of the two nonmatchings .s files (addresses/encodings stripped) is
+ * EMPTY - verified against asm/ov_SC03_090/.../func_8018B028.s, the same
+ * family template. So the banked body is reused VERBATIM, only the
+ * file-local type/macro suffixes renamed to _80188C04.
+ *
+ * DECLARATION SURFACE (whole-TU one-pass grep, D2):
+ * - src/ov_SC03_089/ov_SC03_089_jr_8017CA80.c has NO prototype and NO call
+ * for func_80188C04 (only the INCLUDE_ASM at :7482). `D_80188C04` hits
+ * elsewhere in src/ are a DIFFERENT symbol in other overlays.
+ * - `extern u8 *D_800A5E60;` is function-scope here, identical in shape to
+ * the TU's own function-scope decls at :2815 and :3431.
+ * - The TU expands ZERO DEFINE_func_*()/DEFINE_data_*() macros from
+ * engine_core.h (noted in-file at :5728), and engine_core.h contains no
+ * PTag_/Ft4_/Drm_/SR3_/ADDPRIM_ names at all - no type/macro collision,
+ * no repeated-typedef / repeated bare-struct-tag C89 error.
+ *
+ * The levers that make this body byte-true are documented in full on the
+ * banked twin (giv record order, the 1-unit allocno priority flip closed by
+ * the trailing zero-byte dead read on `vtx`, the two real dead computations,
+ * the volatile OT index that preserves the q biv, the uu/vv split copies).
+ * They are reproduced here unchanged; the trailing
+ * __asm__ __volatile__("" ::"r"(vtx));
+ * placement is load-bearing - do not move it.
+ */
+#include "common.h"
+
+typedef struct {
+ u32 addr : 24;
+ u32 len : 8;
+} PTag_80188C04;
+
+typedef struct {
+ PTag_80188C04 tag;
+ u8 r0, g0, b0, code;
+ u16 x0, y0;
+ u8 u0, v0;
+ u16 clut;
+ u16 x1, y1;
+ u8 u1, v1;
+ u16 tpage;
+ u16 x2, y2;
+ u8 u2, v2;
+ u16 pad2;
+ u16 x3, y3;
+ u8 u3, v3;
+ u16 pad3;
+} Ft4_80188C04;
+
+typedef struct {
+ PTag_80188C04 tag;
+ u32 code0;
+} Drm_80188C04;
+
+#define ADDPRIM_80188C04(o, p) \
+ (((PTag_80188C04 *)(p))->addr = ((PTag_80188C04 *)(o))->addr, \
+ ((PTag_80188C04 *)(o))->addr = (u32)(p))
+
+/* lhu / sll 16 / sra 19 : signed 13-bit field held at bit 3 of a u16 */
+#define SR3_80188C04(a) (((s32)(*(u16 *)(a) << 16)) >> 19)
+
+void func_80188C04(void *ent, void *spr, u32 *q, u32 *ot)
+{
+ extern u8 *D_800A5E60;
+ register s32 zr __asm__("$0");
+
+ Ft4_80188C04 *poly;
+ Drm_80188C04 *dm;
+ s32 vtx;
+ u32 flags;
+ s32 tp, abr, code, shift;
+ u16 x;
+ u32 y;
+ s32 tpage, clut, cy;
+ s32 su, sv, uu, vv;
+ u16 fl;
+ s32 i, m;
+ u32 b;
+
+ poly = (Ft4_80188C04 *)D_800A5E60;
+ fl = *(u16 *)((s32)ent + 0x1E) & 0x8000;
+ flags = *(u32 *)((s32)ent + 4);
+ tp = (flags >> 24) & 3;
+ shift = 2 - tp;
+ x = *(u16 *)((s32)ent + 0x28) + (*(s16 *)((s32)spr + 4) >> shift);
+ y = *(u16 *)((s32)ent + 0x2A) + *(u16 *)((s32)spr + 6);
+ vtx = *(s32 *)((s32)ent + 0x20);
+ D_800A5E60 += 0xF0;
+ if (flags & 0x40000000) {
+ code = 0x2E;
+ abr = (flags >> 28) & 3;
+ } else {
+ code = 0x2C;
+ abr = 1;
+ }
+ tpage = (tp << 7) | (abr << 5) | ((y & 0x100) >> 4) | ((x & 0x3C0) >> 6) |
+ ((y & 0x200) << 2);
+ b = *(u8 *)((s32)ent + 0x27);
+ cy = (b + 0x100) << 6;
+ if (b < 0xE0) {
+ clut = cy | 0x16;
+ } else {
+ clut = cy | 0x10;
+ }
+ {
+ s32 t = ((x - ((tpage & 0xF) << 6)) << shift) +
+ (*(u16 *)((s32)spr + 4) & ((1 << shift) - 1));
+ su = t + zr;
+ __asm__ __volatile__("" ::"r"(t + *(u8 *)((s32)spr + 2) - 1));
+ __asm__ __volatile__("" ::"r"(t));
+ }
+ y = y & 0xFFFF;
+ if (tpage & 0x10) {
+ sv = y - 0x100;
+ } else {
+ sv = y + zr;
+ }
+ __asm__ __volatile__("" ::"r"(sv + *(u8 *)((s32)spr + 3) - 1));
+
+ i = 1;
+ uu = su;
+ vv = sv;
+ for (; i < 13; i += 2, poly++) {
+ s32 k = (i - 1) * 4;
+ __asm__ __volatile__("" ::"r"(i));
+ poly->tag.len = 9;
+ poly->code = code;
+ poly->tpage = tpage;
+ poly->u2 = su;
+ poly->v2 = sv;
+ poly->u0 = SR3_80188C04(vtx + k + 0x10) + uu;
+ poly->v0 = SR3_80188C04(vtx + k + 0x12) + vv;
+ poly->u1 = SR3_80188C04(vtx + i * 4 + 0x10) + uu;
+ poly->v1 = SR3_80188C04(vtx + i * 4 + 0x12) + vv;
+ /* k2 is recorded as a giv HERE, AFTER the u1/v1 mem giv. */
+ {
+ s32 k2 = (i + 1) * 4;
+ poly->u3 = SR3_80188C04(vtx + k2 + 0x10) + uu;
+ poly->v3 = SR3_80188C04(vtx + k2 + 0x12) + vv;
+ }
+ poly->clut = clut;
+ __asm__ __volatile__("" ::"r"(i), "r"(i));
+ poly->r0 = *(u8 *)((s32)ent + 0x24);
+ poly->g0 = *(u8 *)((s32)ent + 0x25);
+ poly->b0 = *(u8 *)((s32)ent + 0x26);
+ poly->x0 = ((u16 *)q)[i * 2];
+ poly->y0 = ((u16 *)q)[i * 2 + 1];
+ poly->x1 = ((u16 *)q)[i * 2 + 2];
+ poly->y1 = ((u16 *)q)[i * 2 + 3];
+ poly->x2 = ((u16 *)q)[0];
+ poly->y2 = ((u16 *)q)[1];
+ poly->x3 = ((u16 *)q)[i * 2 + 4];
+ poly->y3 = ((u16 *)q)[i * 2 + 5];
+ if (fl != 0) {
+ ADDPRIM_80188C04(&ot[*(s32 *)((s32)q + 0x34 + (i >> 1) * 4)], poly);
+ } else {
+ ADDPRIM_80188C04(ot, poly);
+ }
+ }
+ poly[-1].x3 = ((u16 *)q)[2];
+ poly[-1].y3 = ((u16 *)q)[3];
+ poly[-1].u3 = su + SR3_80188C04(vtx + 0x10);
+ poly[-1].v3 = sv + SR3_80188C04(vtx + 0x12);
+
+ if (flags & 0x40000000) {
+ dm = (Drm_80188C04 *)poly;
+ if (fl != 0) {
+ m = 0;
+ D_800A5E60 += 0x30;
+ do {
+ m++;
+ dm->tag.len = 1;
+ dm->code0 = (abr << 5) | 0xE100000A;
+ ADDPRIM_80188C04(&ot[*(volatile s32 *)((s32)q + 0x34)], dm);
+ q = (u32 *)((s32)q + 4);
+ dm++;
+ } while (m < 6);
+ } else {
+ dm->code0 = (abr << 5) | 0xE100000A;
+ D_800A5E60 += 8;
+ dm->tag.len = 1;
+ ADDPRIM_80188C04(ot, dm);
+ /* Zero-byte live-range stretch: puts vtx's allocno priority inside
+ * the only admissible window. Placement is load-bearing. */
+ __asm__ __volatile__("" ::"r"(vtx));
+ }
+ }
+}
-INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017CA80", func_80188C04);
void func_80189124(void) {
}
diff --git a/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c b/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c
index 3aed9b4df..03524beb2 100644
--- a/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c
+++ b/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c
@@ -3857,7 +3857,81 @@ void func_8017C880(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8017AE2C", func_8017C95C);
+
+
+/* func_8017C95C -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017C95C;
+
+void func_8017C95C(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017C95C D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017C95C m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c b/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c
index 6dadf7aa7..0bacf4808 100644
--- a/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c
+++ b/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c
@@ -4140,7 +4140,81 @@ void func_8017E79C(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_jr_8017C294", func_8017E878);
+
+
+/* func_8017E878 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017E878;
+
+void func_8017E878(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017E878 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017E878 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c b/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c
index 0b83b270c..6fc133cd0 100644
--- a/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c
+++ b/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c
@@ -3420,7 +3420,264 @@ void func_8017E170(void *a0) {
INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_jr_8017BEBC", func_8017E270);
-INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_jr_8017BEBC", func_8017E2EC);
+/* func_8017E2EC — ov_SC03_114 (296 ins, match_one MATCH).
+ *
+ * Billboard sprite: RTPS the entity origin through the global matrix D_800AF648,
+ * cull on the GTE flag + OT index range, build a Z-rotated 2D basis with
+ * RotMatrixZ, RTPS the +0x20 corner offset, emit TWO POLY_F4 packets out of the
+ * D_800A5E60 bump allocator, addPrim() both into the OT slot, and (when
+ * flags & 0x40000000) append a third 8-byte DR_MODE (0xE1......) packet.
+ *
+ * LEVERS (each byte-checked against asm/.../func_8017E2EC.s)
+ * §135-4 MATRIX init is written in NATURAL row order (m00,m01,m02,m10,m11,...).
+ * The `lhu 0x18($s1)` loads are register-based and therefore ordered
+ * against EVERY $sp store (sched.md §14), so the 2nd load's source
+ * position is what fixes the whole 16-insn window; the two `sh` stores
+ * it feeds then sink on their own. Writing m11 last (to mimic the asm's
+ * store order) pins the 2nd load past all the stores = 15 mismatches.
+ * §135-4 `D_800A5E60 = p2;` must be written BEFORE the last `addPrim` half —
+ * the two stores are disambiguated (/s + symbol vs register base), so
+ * SOURCE order decides, and it is what puts `sw $v0,0($a2)` in the
+ * `beqz $t2` delay slot instead of a stolen `addiu $v0,$a1,0x38`.
+ * §137/S2 THE TAG TEMPS. Each `getaddr` read (`lw 0x0($a1)` / `0x18($a1)` /
+ * `0x30($a1)`) is a single-set pseudo => sched1's BIRTHING BOOST sinks
+ * it to just before its `and`, costing the 4th filler slot in the
+ * vertex-store window (nop at idx 221, +1 insn). Binding them to ONE
+ * reused local kills the boost (REG_N_SETS>1) and the loads take their
+ * target positions — but a 2-death local is REFUSED by local-alloc
+ * (local-alloc.c:472 needs reg_n_deaths==1), so it becomes a GLOBAL
+ * allocno and loses the low register ($a0 instead of $v1, and the `and`
+ * can no longer coalesce destructively). The two `register` pins
+ * restore exactly the target's dispositions; both are load-bearing
+ * (pin-trim: drop $a0 => 34 mismatches, drop $v1 => 6, drop both => 24).
+ * S2 `pkt` must be SINGLE-SET: the 2nd `D_800A5E60` read goes to its own
+ * local `pkb`, which boosts `lw $a1,D_800A5E60` and wins the pri-1 tie
+ * against `lhu 0x66($sp)` at idx 124. That tie is INVARIANT under every
+ * statement permutation (8 probed) — the lever is the boost, not LUID.
+ * §135-1 `idx` is u32 (unsigned compare `sltiu`); the sign test is the
+ * explicit `(s32)idx < 0` that emits `bgez`.
+ * T-form `otp = (u32 *)((idx << 2) + ot)` — index FIRST, giving
+ * `addu $a2,$v0,$s4`; `ot + (idx << 2)` emits the operands reversed.
+ *
+ * DECLARATIONS: the TU already defines gte_ldv0/gte_rtps/gte_stsxy/gte_stflg/
+ * gte_stszotz at file scope (L2697-2806) — reproduced here VERBATIM so the
+ * redefinition is identical (C89 legal, no diagnostic). gte_SetRotMatrix,
+ * gte_SetTransMatrix, gte_stsz, RD16 and RW32 appear nowhere under src/.
+ * D_800B9A02 is spelled `short` exactly as the TU's file-scope L2468 and
+ * func_8017BEBC's L2822 do; D_800AF648, D_800A5E60, D_800A6610 and RotMatrixZ
+ * have no file-scope decl in this TU (engine_core.h carries D_800AF648 /
+ * D_800B9A02 only inside DEFINE_func macro BODIES, i.e. block scope), so each is
+ * block-scoped here to keep the blast radius on the rest of the TU at zero
+ * (§103/T51, the func_80185944 precedent).
+ */
+
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_8017E2EC(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern short D_800B9A02;
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
diff --git a/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c b/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c
index 2b6f8caff..3e93f3bff 100644
--- a/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c
+++ b/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c
@@ -4291,7 +4291,81 @@ void func_8017E948(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017AE2C", func_8017EA24);
+
+
+/* func_8017EA24 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017EA24;
+
+void func_8017EA24(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017EA24 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017EA24 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c b/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c
index 99a5d5340..c0bc5d2fe 100644
--- a/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c
+++ b/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c
@@ -4285,7 +4285,81 @@ void func_8017E948(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017AE2C", func_8017EA24);
+
+
+/* func_8017EA24 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017EA24;
+
+void func_8017EA24(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017EA24 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017EA24 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC03_125/ov_SC03_125_jr_8017AE2C.c b/src/ov_SC03_125/ov_SC03_125_jr_8017AE2C.c
index 8cc7b8a98..9938ce3d7 100644
--- a/src/ov_SC03_125/ov_SC03_125_jr_8017AE2C.c
+++ b/src/ov_SC03_125/ov_SC03_125_jr_8017AE2C.c
@@ -4245,7 +4245,81 @@ void func_8017CFE0(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125_jr_8017AE2C", func_8017D0BC);
+
+
+/* func_8017D0BC -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017D0BC;
+
+void func_8017D0BC(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017D0BC D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017D0BC m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c b/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c
index cda5d2a77..c82e7d3cb 100644
--- a/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c
+++ b/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c
@@ -6010,7 +6010,230 @@ void func_8018EEB0(void *a0) {
INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018EFB0);
-INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018F02C);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_8018F02C(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
diff --git a/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c b/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c
index 4f61a9857..359d5300c 100644
--- a/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c
+++ b/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c
@@ -3549,7 +3549,230 @@ void func_8017F72C(void *a0) {
INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_jr_8017BEBC", func_8017F82C);
-INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_jr_8017BEBC", func_8017F8A8);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_8017F8A8(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
diff --git a/src/ov_SC04_020/ov_SC04_020_jr_8017AE2C.c b/src/ov_SC04_020/ov_SC04_020_jr_8017AE2C.c
index ca7373f28..c9108fa18 100644
--- a/src/ov_SC04_020/ov_SC04_020_jr_8017AE2C.c
+++ b/src/ov_SC04_020/ov_SC04_020_jr_8017AE2C.c
@@ -4245,7 +4245,81 @@ void func_8017CFE0(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020_jr_8017AE2C", func_8017D0BC);
+
+
+/* func_8017D0BC -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017D0BC;
+
+void func_8017D0BC(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017D0BC D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017D0BC m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC05_004/ov_SC05_004_jr_8017BEBC.c b/src/ov_SC05_004/ov_SC05_004_jr_8017BEBC.c
index 6c2831658..c8ee0ddf6 100644
--- a/src/ov_SC05_004/ov_SC05_004_jr_8017BEBC.c
+++ b/src/ov_SC05_004/ov_SC05_004_jr_8017BEBC.c
@@ -3834,7 +3834,81 @@ void func_8017DA24(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004_jr_8017BEBC", func_8017DB00);
+
+
+/* func_8017DB00 -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017DB00;
+
+void func_8017DB00(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017DB00 D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017DB00 m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC05_018/ov_SC05_018_jr_8017AE2C.c b/src/ov_SC05_018/ov_SC05_018_jr_8017AE2C.c
index d216cafd8..c83870bad 100644
--- a/src/ov_SC05_018/ov_SC05_018_jr_8017AE2C.c
+++ b/src/ov_SC05_018/ov_SC05_018_jr_8017AE2C.c
@@ -4245,7 +4245,81 @@ void func_8017CFE0(s16 *a0) {
}
-INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018_jr_8017AE2C", func_8017D0BC);
+
+
+/* func_8017D0BC -- ov_SC02_011 / ov_SC02_011_jr_8017AE2C [target: 133 ins]
+ *
+ * Structural twin of func_8017D0BC (ov_SC03_002/ov_SC03_002_jr_8017AE2C.c),
+ * banked [MATCH, 133 ins] this session -- same jr_8017AE2C shared layout,
+ * identical struct-offset chain (a0+0x6/0xA/0xE/0x10/0x12/0x16/0x18/0x1A) and
+ * identical call sequence (func_80133784 -> ratan2 x2 -> angle-wrap ->
+ * RotMatrixY -> ApplyMatrixSV -> func_8012CEB0). Reused verbatim per §136c
+ * sibling-first (declaration + expression forms are already byte-proven for
+ * this exact body).
+ *
+ * §136 L1/RC-5 note carried from the twin: `ang` (second ratan2 result) is a
+ * GLOBAL allocno spanning the +/-0x480 arms, while the `ang - base` compare
+ * temp is a LOCAL allocno in the same block; unpinned gcc hands the local
+ * temp $v0 and pushes `ang` to $v1 (REGALLOC-PERM). Pinning `ang` to $v0
+ * fixes the swap, and reusing the now-dead `ang` as the a0[0x6] scratch
+ * (instead of a fresh local) avoids stealing back the $v0 slot.
+ */
+
+typedef struct { s32 w[8]; } Mtx8_8017DE10_8017D0BC;
+
+void func_8017D0BC(s32 a0) {
+ extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
+ extern s32 ratan2(s32 a0, s32 a1);
+ extern s16 D_801152B0;
+ extern s16 D_801152B4;
+ extern s32 func_80133784(s32 a0, void *a1, s32 a2);
+ extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
+ extern void RotMatrixY(s32 a0, void *a1);
+ extern Mtx8_8017DE10_8017D0BC D_800AE620;
+
+ u8 in[8];
+ u8 out[8];
+ Mtx8_8017DE10_8017D0BC m;
+ s32 base;
+ register s32 ang __asm__("$2");
+ s16 arg;
+
+ *(s16 *)(in + 0) = *(u16 *)(a0 + 0x6) + *(u16 *)(a0 + 0x12);
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE) + *(u16 *)(a0 + 0x1A);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + 8;
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE);
+ if ((func_80133784(1, &in[0], (s32)&out[0]) & 0xC000) != 0) {
+ base = ratan2(D_801152B0, D_801152B4) & 0xFFF;
+ ang = ratan2(*(s32 *)(a0 + 0x10), *(s32 *)(a0 + 0x18)) & 0xFFF;
+ if ((s16)(ang - base) < 0) {
+ ang += 0x480;
+ } else {
+ ang -= 0x480;
+ }
+ arg = base - ang;
+ ang = *(u16 *)(a0 + 0x6);
+ *(s16 *)(in + 0) = ang;
+ *(s16 *)(in + 2) = *(u16 *)(a0 + 0xA);
+ *(s16 *)(in + 4) = *(u16 *)(a0 + 0xE);
+ m = D_800AE620;
+ RotMatrixY(arg, &m);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x12);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0x16);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0x1A);
+ ApplyMatrixSV(&m, &out[0], &out[0]);
+ *(s16 *)(out + 0) = *(u16 *)(a0 + 0x6) + ((s16)*(u16 *)(out + 0) >> 1);
+ *(s16 *)(out + 2) = *(u16 *)(a0 + 0xA) + ((s16)*(u16 *)(out + 2) >> 1);
+ *(s16 *)(out + 4) = *(u16 *)(a0 + 0xE) + ((s16)*(u16 *)(out + 4) >> 1);
+ if ((func_8012CEB0((s32)&in[0], (s32)&out[0], 0) & 0x2000) != 0) {
+ *(s16 *)(a0 + 0x6) = *(u16 *)(out + 0);
+ *(s16 *)(a0 + 0xA) = *(u16 *)(out + 2);
+ *(s16 *)(a0 + 0xE) = *(u16 *)(out + 4);
+ }
+ }
+}
+
extern int func_80178970(void);
diff --git a/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c b/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c
index e30f7a66f..a2920bc04 100644
--- a/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c
+++ b/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c
@@ -4046,7 +4046,6 @@ typedef struct { u32 xx, yy, zz; u32 nprim; u32 *prim; } Part35C;
extern s32 func_800491EC(void);
extern void func_800547D8(s32, Mtx35C *);
extern void func_80052E38(Mtx35C *);
-extern u8 D_800A6610[];
extern s16 D_800B9A02;
#define gte_ldv0(r0) __asm__ volatile ( \
@@ -4141,6 +4140,10 @@ extern s16 D_800B9A02;
void func_8017E35C(s32 arg0)
{
+ /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every
+ LATER function in this TU, which blocks a byte-true decl of a different type.
+ Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */
+ extern u8 D_800A6610[];
/* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every
LATER function in this TU, which blocks a byte-true decl of a different type.
Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */
@@ -7322,7 +7325,230 @@ void func_801879B8(void *a0) {
INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80187AB8);
-INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80187B34);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_80187B34(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
diff --git a/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c b/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c
index bb0d28c0d..d4c7d09a2 100644
--- a/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c
+++ b/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c
@@ -3875,7 +3875,230 @@ void func_801814DC(void *a0) {
INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_8017BEBC", func_801815DC);
-INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_8017BEBC", func_80181658);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_80181658(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
diff --git a/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c b/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c
index 7e1ddfbf8..2bd3b93d1 100644
--- a/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c
+++ b/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c
@@ -3639,7 +3639,245 @@ s32 func_8017E5C8(void) {
}
-INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017E5D0);
+/* func_8017E5D0 — draws a 4-segment perspective-scaled "trail/shadow" fan of
+ * gouraud-shaded quads (POLY_G4-shaped, stride 0x24) behind an object.
+ *
+ * Derivation notes (no banked sibling existed — first crack of a 6-member family):
+ * - GTE matrix load + RotTransSV + RotTransPers pipeline matches the byte-proven
+ * gte_SetRotMatrix/gte_SetTransMatrix macros (ov_SC03_099_jr_8017BEBC.c) and the
+ * engine_core.h RotTransPers canonical form.
+ * - D_800A651C OT-table lookup uses the canonical engine_core.h idiom:
+ * `*(s32*)((s8*)&D_800A651C + ((u16)D_800B9A02 * 0x14))` (DEFINE_func_8012D4B4 et al).
+ * - The per-prim struct (0x24-byte stride) decodes as a libgpu POLY_G4: tag(4,
+ * AddPrim-owned except the `len` top byte we set), 4x{rgb+code/pad(4), x,y(4)}.
+ * All 14 fields matched a `base = s0 - 0x22` model with s0 anchored at the LAST
+ * field (y3) — negative-offset addressing off that anchor pointer.
+ * - D_8019E198/199/19A/19B, D_8019E178/179/17A/17B, D_8019E188/189/18A/18B are each
+ * individually-addressed consecutive byte tables (cookbook idiom: multi-symbol
+ * byte array, same class as ov_SC03_101's D_8019E170..D_8019E178 chain) — accessed
+ * via `*(u8*)((s32)&D_8019Exxx + i)`, NOT array indexing.
+ * - RotTransSV / func_8004914C / func_800491AC are ALREADY file-scope declared
+ * above the splice point in this TU (void* params) — reused verbatim, not redeclared.
+ *
+ * CLOSING RESIDUAL (S34, gcc-2.7.2-map/sched.md §S2 — "CREATE the boost"):
+ * The 262/265 draft emitted `lhu $a2,0x54(sp)` BEFORE the `lui/lhu %hi/%lo(D_800B9A02)`
+ * pair; the target has the pair first. All four insns tie at pri 1, so the pick was
+ * decided by adjust_priority's BIRTHING BOOST (sched.c:2507 / birthing_insn_p:2469):
+ * a SET(REG,..) whose dest has REG_N_SETS==1 is raised to max_priority and, because
+ * schedule_block runs BACKWARD, is PICKED EARLY == PLACED LATE. `sy` had TWO sets
+ * (`sy = L.sy0` then `sy = sy + sc`) so its load was never boosted and could not sink
+ * past the D_800B9A02 pair. Giving the accumulate its own single-set local (`sye`)
+ * makes `sy = L.sy0` a single-set def -> boosted -> the whole 4-load group lands in
+ * the target order. (Splitting `sx` the same way OVER-shoots: it re-groups the
+ * 0x36/0x40 store cluster — 9 mismatches. ONLY `sy` is split. Byte-verified: the
+ * three tested variants scored sx-only 9, both 5, sy-only 0.)
+ */
+
+extern s32 RotTransPers(s32 a0, s32 a1, s32 *a2, s32 *a3);
+extern void *func_80010A08(s32 a0);
+extern s32 GetTPage(s32 a0, s32 a1, s32 a2, s32 a3);
+extern s32 func_8005A600(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4);
+extern s32 AddPrim(s32 a0, void *a1);
+
+extern u8 D_8019E164;
+extern s32 D_8019E16C[];
+
+extern u8 D_8019E178;
+extern u8 D_8019E179;
+extern u8 D_8019E17A;
+extern u8 D_8019E17B;
+
+extern u8 D_8019E188;
+extern u8 D_8019E189;
+extern u8 D_8019E18A;
+extern u8 D_8019E18B;
+
+extern u8 D_8019E198;
+extern u8 D_8019E199;
+extern u8 D_8019E19A;
+extern u8 D_8019E19B;
+
+extern s32 D_800A651C;
+extern s32 D_80126950;
+extern s16 D_800B9A02;
+
+extern void func_8004914C(void *a0);
+extern void func_800491AC(void *a0);
+extern void RotTransSV(void *a0, void *a1, void *a2);
+
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+
+/* §37/§124 SELF-axis: the TU declares `extern void func_8017E5D0(void);` (L3765) but the
+ byte-true definition takes a pointer. Define under a private C name bound to the real
+ symbol so both live in one TU — zero blast radius on every caller. */
+extern void aF8017E5D0(void *a0) __asm__("func_8017E5D0");
+void aF8017E5D0(void *a0)
+{
+ extern u8 D_800AF648;
+
+ s32 primPtrs[4]; /* sp+0x18 */
+ s16 sv0[4]; /* sp+0x28 : RotTransSV out */
+ s16 sxArr[8]; /* sp+0x30 */
+ s16 syArr[8]; /* sp+0x40 */
+ struct {
+ s32 flag; /* sp+0x50 */
+ u16 sx0; /* sp+0x54 */
+ u16 sy0; /* sp+0x56 */
+ s32 p; /* sp+0x58 */
+ } L;
+
+ s32 m;
+ register s32 cnt __asm__("$8");
+ s32 sc;
+ s32 sx, sy;
+ s32 sye; /* single-set split of sy (see header note: §S2 birthing boost) */
+ s32 d;
+ register s32 ot __asm__("$9");
+ s32 otAddr;
+ void *buf;
+ s32 tpage;
+ u8 *prim;
+ register s8 *fp __asm__("$16");
+ s32 i;
+
+ m = *(s32 *)((s32)a0 + 0x20) + 0x34;
+ gte_SetRotMatrix(m);
+ gte_SetTransMatrix(m);
+
+ RotTransSV(&D_8019E164, sv0, &L.flag);
+
+ func_8004914C(&D_800AF648);
+ func_800491AC(&D_800AF648);
+
+ cnt = RotTransPers((s32)sv0, (s32)&L.sx0, &L.p, &L.flag);
+ if (cnt <= 0) {
+ return;
+ }
+ if (L.flag < 0) {
+ return;
+ }
+ cnt = cnt << 2;
+
+ sc = ((D_80126950 + 0x1F4) * 3) << 4;
+ sc = sc / cnt;
+
+ ot = *(s32 *)((s8 *)&D_800A651C + ((u16)D_800B9A02 * 0x14));
+ sx = L.sx0;
+ sy = L.sy0;
+
+ sxArr[2] = sx;
+ syArr[2] = sy;
+
+ otAddr = ot + cnt;
+
+ {
+ register s32 t __asm__("$2");
+
+ t = sx - sc;
+ sxArr[0] = t;
+
+ d = (sc * 179) >> 8;
+
+ t = sx - d;
+ sxArr[1] = t;
+ t = sx + d;
+ sxArr[3] = t;
+ sx = sx + sc;
+
+ t = sy - sc;
+ syArr[0] = t;
+ t = sy - d;
+ sxArr[4] = sx;
+ syArr[1] = t;
+ syArr[3] = sy + d;
+ sye = sy + sc;
+ }
+
+ syArr[4] = sye;
+
+ buf = func_80010A08(0x9C);
+
+ if (buf == 0) {
+ return;
+ }
+
+ tpage = GetTPage(0, 1, 0, 0);
+ func_8005A600((s32)buf, 0, 0, (u16)tpage, 0);
+
+ {
+ register s32 t0c __asm__("$2");
+ t0c = (s32)((u8 *)buf + 0xC);
+ prim = (u8 *)t0c;
+ }
+
+ primPtrs[1] = (s32)((u8 *)buf + 0x30);
+ primPtrs[2] = (s32)((u8 *)buf + 0x54);
+ primPtrs[0] = (s32)prim;
+ primPtrs[3] = (s32)((u8 *)buf + 0x78);
+
+ {
+ register s32 *table __asm__("$21");
+ register s8 *cbase __asm__("$18");
+ table = D_8019E16C;
+ cbase = (s8 *)primPtrs;
+ fp = (s8 *)prim + 0x22;
+
+ i = 0;
+ for (; i < 0x10; i += 4) {
+ *(s32 *)(fp - 0x1E) = table[*(u8 *)((s32)&D_8019E198 + i)];
+ *(s32 *)(fp - 0x16) = table[*(u8 *)((s32)&D_8019E199 + i)];
+ *(s32 *)(fp - 0xE) = table[*(u8 *)((s32)&D_8019E19A + i)];
+
+ {
+ s32 rgb3 = table[*(u8 *)((s32)&D_8019E19B + i)];
+ *(u8 *)(fp - 0x1F) = 8;
+ *(u8 *)(fp - 0x1B) = 0x3A;
+ *(s32 *)(fp - 0x6) = rgb3;
+ }
+
+ *(s16 *)(fp - 0x1A) = *(s16 *)(cbase + 0x18 + (*(u8 *)((s32)&D_8019E178 + i) << 1));
+ *(s16 *)(fp - 0x12) = *(s16 *)(cbase + 0x18 + (*(u8 *)((s32)&D_8019E179 + i) << 1));
+ *(s16 *)(fp - 0xA) = *(s16 *)(cbase + 0x18 + (*(u8 *)((s32)&D_8019E17A + i) << 1));
+ *(s16 *)(fp - 0x2) = *(s16 *)(cbase + 0x18 + (*(u8 *)((s32)&D_8019E17B + i) << 1));
+
+ *(s16 *)(fp - 0x18) = *(s16 *)(cbase + 0x28 + (*(u8 *)((s32)&D_8019E188 + i) << 1));
+ *(s16 *)(fp - 0x10) = *(s16 *)(cbase + 0x28 + (*(u8 *)((s32)&D_8019E189 + i) << 1));
+ *(s16 *)(fp - 0x8) = *(s16 *)(cbase + 0x28 + (*(u8 *)((s32)&D_8019E18A + i) << 1));
+ *(s16 *)(fp - 0x0) = *(s16 *)(cbase + 0x28 + (*(u8 *)((s32)&D_8019E18B + i) << 1));
+
+ AddPrim(otAddr, prim);
+
+ prim += 0x24;
+ fp += 0x24;
+ }
+ }
+
+ AddPrim(otAddr, buf);
+}
+
extern u16 D_80126B62;
extern u16 D_80126B66;
diff --git a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c
index 4171fb402..604a85bc0 100644
--- a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c
+++ b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c
@@ -7645,7 +7645,230 @@ INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018CB8
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018CC88);
-INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018CD04);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_8018CD04(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing
// @stuck: none — MATCH (99 ins). short* for param_2/param_3: gcc emits lh where sign is live (<<1 for signed div), lhu where truncated to short (arith result / direct copy)
diff --git a/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c b/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c
index 682f98e2d..4d7c0327d 100644
--- a/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c
+++ b/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c
@@ -5800,7 +5800,230 @@ void func_80187D60(void *a0) {
INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80187E60);
-INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80187EDC);
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_SetRotMatrix(r0) __asm__ volatile ( \
+ "lw $12, 0( %0 );" \
+ "lw $13, 4( %0 );" \
+ "ctc2 $12, $0;" \
+ "ctc2 $13, $1;" \
+ "lw $12, 8( %0 );" \
+ "lw $13, 12( %0 );" \
+ "lw $14, 16( %0 );" \
+ "ctc2 $12, $2;" \
+ "ctc2 $13, $3;" \
+ "ctc2 $14, $4" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_SetTransMatrix(r0) __asm__ volatile ( \
+ "lw $12, 20( %0 );" \
+ "lw $13, 24( %0 );" \
+ "ctc2 $12, $5;" \
+ "lw $14, 28( %0 );" \
+ "ctc2 $13, $6;" \
+ "ctc2 $14, $7" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "$13", "$14" )
+#define gte_ldv0(r0) __asm__ volatile ( \
+ "lwc2 $0, 0( %0 );" \
+ "lwc2 $1, 4( %0 )" \
+ : \
+ : "r"( r0 ) )
+#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
+#define gte_stsxy(r0) __asm__ volatile ( \
+ "swc2 $14, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stsz(r0) __asm__ volatile ( \
+ "swc2 $19, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+#define gte_stszotz(r0) __asm__ volatile ( \
+ "mfc2 $12, $19;" \
+ "nop;" \
+ "sra $12, $12, 2;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define gte_stflg(r0) __asm__ volatile ( \
+ "cfc2 $12, $31;" \
+ "nop;" \
+ "sw $12, 0( %0 )" \
+ : \
+ : "r"( r0 ) \
+ : "$12", "memory" )
+#define RD16(p) (((struct { u16 v; } *)(p))->v)
+#define RW32(p) (((struct { u32 v; } *)(p))->v)
+
+void func_80187EDC(void *a0)
+{
+ extern u8 D_800AF648;
+ extern u8 *D_800A5E60;
+ extern u8 D_800A6610[];
+ extern void RotMatrixZ(s32 a0, void *a1);
+
+ u8 stk[0x60]; /* sp+0x10 .. sp+0x6F */
+ u32 flags;
+ u32 idx;
+ u32 ot;
+ u32 t2;
+ u8 *pkt;
+ u8 *p1;
+ u8 *p2;
+ u8 *pkb;
+ s32 d;
+ u32 *otp;
+ register u32 tv __asm__("$3"); /* §137 pin — see header */
+ register u32 tv2 __asm__("$4"); /* §137 pin — see header */
+
+ u8 *rotm;
+
+ flags = *(u32 *)((s32)a0 + 4);
+ rotm = &D_800AF648;
+
+ gte_SetRotMatrix(rotm);
+ gte_SetTransMatrix(rotm);
+ gte_ldv0((s32)a0 + 8);
+ gte_rtps();
+ gte_stsxy(stk);
+ gte_stflg(stk + 0x48);
+ gte_stsz(stk + 0x4c);
+ gte_stszotz(stk + 0x50);
+
+ if ((*(u32 *)(stk + 0x48) & 0xFFFFEFFF) == 0) {
+ idx = *(s32 *)(stk + 0x50) + 1;
+ ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
+ {
+ u16 flags2 = *(u16 *)((s32)a0 + 0x2c);
+ if ((flags2 & 0xC000) != 0) {
+ if ((flags2 & 0xC000) == 0xC000) {
+ idx = idx - (flags2 & 0xFFF);
+ if ((s32)idx < 0) idx = 0;
+ } else {
+ idx = idx + (flags2 & 0xFFF);
+ }
+ }
+ }
+
+ if (idx < 0x1000) {
+ d = (s32)&stk[0x08];
+
+ *(u16 *)(stk + 0x08) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x0a) = 0;
+ *(u16 *)(stk + 0x0c) = 0;
+ *(u16 *)(stk + 0x0e) = 0;
+ *(u16 *)(stk + 0x10) = *(u16 *)((s32)a0 + 0x18);
+ *(u16 *)(stk + 0x12) = 0;
+ *(u16 *)(stk + 0x14) = 0;
+ *(u16 *)(stk + 0x16) = 0;
+ *(u16 *)(stk + 0x18) = 0x1000;
+ *(u32 *)(stk + 0x24) = 0;
+ *(u32 *)(stk + 0x20) = 0;
+ *(u32 *)(stk + 0x1c) = 0;
+
+ RotMatrixZ(*(s16 *)((s32)a0 + 0x14), (void *)d);
+ gte_SetRotMatrix((void *)d);
+ gte_SetTransMatrix((void *)d);
+
+ *(u16 *)(stk + 0x28) = 0x20;
+ *(u16 *)(stk + 0x2a) = 0;
+ *(s16 *)(stk + 0x2c) = (s16)*(u32 *)(stk + 0x4c);
+ gte_ldv0(stk + 0x28);
+ gte_rtps();
+ gte_stsxy(stk + 0x54);
+
+ d = (u16)((s16)(RD16(stk + 0x54)) >> 3);
+ d |= (s32)((s16)(RD16(stk + 0x56)) >> 3) << 16;
+
+ pkt = D_800A5E60;
+ p1 = pkt + 0x18;
+ *(u8 *)(pkt + 0x3) = 5;
+ *(u8 *)(pkt + 0x7) = 0x28;
+ *(u8 *)(p1 + 0x3) = 5;
+ t2 = flags & 0x40000000;
+ *(u8 *)(p1 + 0x7) = 0x28;
+ if (t2 != 0) {
+ *(u8 *)(pkt + 0x7) = *(u8 *)(pkt + 0x7) | 2;
+ *(u8 *)(p1 + 0x7) = *(u8 *)(p1 + 0x7) | 2;
+ }
+ *(u8 *)(pkt + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(pkt + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(pkt + 0x6) = *(u8 *)((s32)a0 + 0x26);
+ *(u8 *)(p1 + 0x4) = *(u8 *)((s32)a0 + 0x24);
+ *(u8 *)(p1 + 0x5) = *(u8 *)((s32)a0 + 0x25);
+ *(u8 *)(p1 + 0x6) = *(u8 *)((s32)a0 + 0x26);
+
+ *(s16 *)(pkt + 0x8) = RD16(stk) + RD16(stk + 0x54);
+ *(s16 *)(pkt + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x56);
+ *(s16 *)(pkt + 0xc) = RD16(stk) - (d >> 16);
+ *(s16 *)(pkt + 0xe) = RD16(stk + 0x02) + d;
+ *(s16 *)(pkt + 0x10) = RD16(stk) + (d >> 16);
+ *(s16 *)(pkt + 0x12) = RD16(stk + 0x02) - d;
+ *(s16 *)(pkt + 0x14) = RD16(stk) - RD16(stk + 0x54);
+ *(s16 *)(pkt + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x8) = RD16(stk) - RD16(stk + 0x56);
+ *(s16 *)(p1 + 0xa) = RD16(stk + 0x02) + RD16(stk + 0x54);
+ *(s16 *)(p1 + 0xc) = RD16(stk) - d;
+ *(s16 *)(p1 + 0xe) = RD16(stk + 0x02) - (d >> 16);
+ *(s16 *)(p1 + 0x10) = RD16(stk) + d;
+ *(s16 *)(p1 + 0x12) = RD16(stk + 0x02) + (d >> 16);
+ *(s16 *)(p1 + 0x14) = RD16(stk) + RD16(stk + 0x56);
+ *(s16 *)(p1 + 0x16) = RD16(stk + 0x02) - RD16(stk + 0x54);
+
+ /* addPrim(otp, pkt); addPrim(otp, p1); */
+ otp = (u32 *)((idx << 2) + ot);
+ tv = RW32(pkt);
+ RW32(pkt) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)pkt & 0xFFFFFF);
+ tv = RW32(p1);
+ RW32(p1) = (tv & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+
+ pkb = D_800A5E60;
+ p2 = pkb + 0x30;
+ D_800A5E60 = p2;
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p1 & 0xFFFFFF);
+
+ if (t2 != 0) {
+ D_800A5E60 = pkb + 0x38;
+ *(u8 *)(p2 + 3) = 1;
+ RW32(p2 + 4) = ((flags >> 23) & 0x60) | 0xE1000000;
+ tv2 = RW32(p2);
+ RW32(p2) = (tv2 & 0xFF000000) | (RW32(otp) & 0xFFFFFF);
+ RW32(otp) = (RW32(otp) & 0xFF000000) | ((u32)p2 & 0xFFFFFF);
+ }
+ }
+ }
+}
+
// @class: loose-typing