diff --git a/docs/MATCHING_COOKBOOK.md b/docs/MATCHING_COOKBOOK.md index 8c12844..0be70b6 100644 --- a/docs/MATCHING_COOKBOOK.md +++ b/docs/MATCHING_COOKBOOK.md @@ -2337,3 +2337,32 @@ tell for a **`2^k − 1` divisor**, not for a large one. time in the phase that one worker's finding closed another worker's negative, and it is the strongest argument for the practice of **recording a named open question rather than a vague failure**: D's write-up is what let C recognise the answer when it arrived from an unrelated row. + +### 143. THE GTE TOKEN IS SHIPPED — the missing registers were `$8-$12`, and the command macro is generic + +Finding 122 declared GTE rows a **blocked class needing a harness token**. The token now exists, and +the gap was smaller than it looked: `include/gtemac.h` already covered `$0-$7` and `$13-$31` **but +not `$8-$12`** — which is where **IR1/IR2/IR3 (`$9/$10/$11`)** live — and it had **no macro for the +GTE command instruction itself** (only `gte_nRTPS()`, a single proved value). + +**Added:** +- `gte_ldIR1/2/3`, `gte_stIR1/2/3` (`mtc2`/`mfc2` `$9`/`$10`/`$11`) +- `gte_ldMAC1/2/3`, `gte_stMAC1/2/3` (`$25`/`$26`/`$27`) +- **`gte_cmd(field)`** — a **generic** macro, `__asm__ volatile ("cop2 " #field)`, so any command whose + 25-bit field has been read off the original can be emitted without first earning a semantic name. + +**Verified against the original, not assumed.** The field values are confirmed by counting them over +the whole binary: **`0x486012` ×51, `0x49E012` ×11, `0x41E012` ×4**, and a test compilation emits +`gte_cmd(0x486012)` → `cop2 0x486012` → **`0x4A486012`**, exactly the original's word. + +**Two harness facts carried forward:** the `cop2` operand is the **25-bit field, not 26** +(`cop2 0x2486012` is an operand-range error — worker A), and a candidate **outside `src/` cannot use +the relative `#include "../include/gtemac.h"`** — use the absolute path or develop in `src/`. + +**Five rows were blocked on this:** worker A's `0x800F9BC8` (268 B) and `0x800F3C60` (352 B), +worker B's `0x8001FAFC` (148 B), worker D's `0x80103434` (268 B) and `0x800F3E18`. **All five have +complete or partial derivations recorded.** They are now a batch, not a wall. + +**The disposition matters as much as the token: these rows were correctly declared BLOCKED rather than +ground.** Three workers independently reached "no amount of spelling will find this" and stopped — and +that is what made the gap visible as a *tooling* problem instead of three separate source puzzles. diff --git a/include/gtemac.h b/include/gtemac.h index 2e1ae63..c6d76e2 100644 --- a/include/gtemac.h +++ b/include/gtemac.h @@ -116,6 +116,29 @@ #define gte_ldDQA(v) __asm__ volatile ("ctc2 %0,$27" : : "r"(v)) #define gte_ldDQB(v) __asm__ volatile ("ctc2 %0,$28" : : "r"(v)) +/* --- IR / MAC registers ($8-$12, $25-$27) -------------------------------- */ + +/* The header originally covered $0-$7 and $13-$31 but NOT $8-$12, which left + * five GTE rows blocked in Phase 11 (worker A's 0x800F9BC8 / 0x800F3C60, + * worker B's 0x8001FAFC, worker D's 0x80103434 / 0x800F3E18). + * + * IR1/IR2/IR3 = $9/$10/$11. Proved by worker B's 0x8001FAFC, which reads + * `mfc2 t0,$12 / mfc2 t1,$13 / mfc2 t2,$14` in the ORIGINAL; the IR1-3 loads + * there are $9/$10/$11 by the same field layout. MAC1-3 = $25/$26/$27 are + * read with `mfc2` after a command in worker A's 0x800F3C60. */ +#define gte_ldIR1(v) __asm__ volatile ("mtc2 %0,$9" : : "r"(v)) +#define gte_ldIR2(v) __asm__ volatile ("mtc2 %0,$10" : : "r"(v)) +#define gte_ldIR3(v) __asm__ volatile ("mtc2 %0,$11" : : "r"(v)) +#define gte_stIR1(r) __asm__ volatile ("mfc2 %0,$9" : "=r"(r)) +#define gte_stIR2(r) __asm__ volatile ("mfc2 %0,$10" : "=r"(r)) +#define gte_stIR3(r) __asm__ volatile ("mfc2 %0,$11" : "=r"(r)) +#define gte_stMAC1(r) __asm__ volatile ("mfc2 %0,$25" : "=r"(r)) +#define gte_stMAC2(r) __asm__ volatile ("mfc2 %0,$26" : "=r"(r)) +#define gte_stMAC3(r) __asm__ volatile ("mfc2 %0,$27" : "=r"(r)) +#define gte_ldMAC1(v) __asm__ volatile ("mtc2 %0,$25" : : "r"(v)) +#define gte_ldMAC2(v) __asm__ volatile ("mtc2 %0,$26" : : "r"(v)) +#define gte_ldMAC3(v) __asm__ volatile ("mtc2 %0,$27" : : "r"(v)) + /* --- commands ------------------------------------------------------------ */ /* The 25-bit COP2 command field is written as `cop2 0x...`, which GNU as @@ -123,6 +146,22 @@ * this batch is nRTPS = 0x180001 (0x80010810, 0x80018CB0). */ #define gte_nRTPS() __asm__ volatile ("cop2 0x180001") +/* Generic form, for the commands whose 25-bit field has been read off the + * original but whose semantic name is not yet earned. GNU as takes the field + * directly, so `gte_cmd(0x486012)` emits exactly 0x4A486012 -- the operand is + * the 25-bit field, NOT 26 (`cop2 0x2486012` is an operand-range error; worker + * A, Phase 11). + * + * Field values CONFIRMED present in the original (counted over the whole + * binary, Phase 11 coordinator): + * 0x486012 x51 -- used by worker A's 0x800F9BC8 and worker D's 0x80103434 + * 0x49E012 x11 -- worker A's 0x800F3C60 + * 0x41E012 x4 -- worker A's 0x800F3C60 + * The low six bits are the GTE command number (0x12 = MVMVA in all three); the + * upper bits select the matrix / vector / translation / shift fields. Do NOT + * name them semantically without evidence -- name them by field value. */ +#define gte_cmd(field) __asm__ volatile ("cop2 " #field) + /* --- BIOS call stubs ----------------------------------------------------- */ /* A PsyQ BIOS stub is `li a0,code` / `syscall`, with the compiler's own