diff --git a/config/regions.tsv b/config/regions.tsv index a8afd2c..30bfc52 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -157,6 +157,7 @@ 0x800579A0 0x800579F0 src/func_800579A0.c 0x800579F0 0x80057A40 src/func_800579F0.c 0x80057AE0 0x80057B30 src/func_80057AE0.c +0x80057B84 0x80057BE8 src/func_80057B84.c 0x80057C30 0x80057C80 src/func_80057C30.c 0x80057DFC 0x80057E04 src/func_80057DFC.c 0x80058230 0x80058288 src/func_80058230.c diff --git a/src/func_80057B84.c b/src/func_80057B84.c new file mode 100644 index 0000000..878c74c --- /dev/null +++ b/src/func_80057B84.c @@ -0,0 +1,57 @@ +/* func_80057B84 — 0x80057B84..0x80057BE8 (100 bytes). + * + * Fourth member of the 0x80057xxx argument-block family, and the one that differs + * structurally from its three matched siblings. + * + * Original words: + * 27BDFFD0 addiu sp,sp,-48 + * 30A300FF andi v1,a1,0xff + * 0003102B sltu v0,zero,v1 + * 00021023 negu v0,v0 + * 93A80040 lbu t0,64(sp) the FIFTH incoming parameter + * 00C24824 and t1,a2,v0 t1 = a2 & mask (a2 or 0) + * 10600003 beqz v1,0x80057BAC + * AFBF0028 _sw ra,40(sp) (delay slot) + * 08015EEC j 0x80057BB0 + * AFA70010 _sw a3,16(sp) (delay slot) outgoing arg 5 = a3 + * AFA00010 sw zero,16(sp) <- 0x80057BAC, outgoing arg 5 = 0 + * 30A200FF andi v0,a1,0xff + * 24050012 li a1,18 + * 2406FFFF li a2,-1 + * 01203821 move a3,t1 + * AFA00014 sw zero,20(sp) outgoing arg 6 = 0 + * AFA00018 sw zero,24(sp) outgoing arg 7 = 0 + * AFA0001C sw zero,28(sp) outgoing arg 8 = 0 + * AFA20020 sw v0,32(sp) outgoing arg 9 = narrowed a1 + * 0C015D99 jal 0x80057664 + * AFA80024 _sw t0,36(sp) (delay slot) outgoing arg 10 = the fifth parameter + * + * **THE BRANCH IS THE TELL, AND IT DISTINGUISHES THIS ROW FROM ITS SIBLINGS.** The three + * matched members select between `a0` and zero, which cc1 compiles **branchlessly** with + * `sltu`+`negu`+`and`. Here **two different values** are selected — outgoing arg 4 is `a2` + * or zero and outgoing arg 5 is `a3` or zero — so the same mask is built for arg 4 while + * arg 5 needs a real `beqz`/`j` pair. So the family contains both spellings, and which one a + * row uses is decided by *how many distinct values are selected*, not by the author's style: + * one value → branchless, two values → one branch. That is a cheap discriminator for the + * remaining rows in this family. + * + * The mask is still built with `sltu`+`negu` (the 0-or-−1 trick) and `negu` appears once + * more, consistent with the toolchain evidence this family has been accumulating. + * + * The callee's ten arguments are: the routine's `a0`, the selector 18, −1, `a2 or 0`, + * `a3 or 0`, three zeros, then the narrowed `a1` and the fifth parameter on the stack. + * + * LIMITS: the selector 18, the mask 0xff and the frame layout are read from the bytes. The + * fifth parameter is `unsigned char` by the single `lbu`. As in the siblings, the outgoing + * argument area is directly visible — six words at 16–36(sp) with `ra` at 40 — so the + * ten-argument model is checkable by arithmetic rather than inferred. + */ + +void func_80057664(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, + int a8, int a9); + +void func_80057B84(int a0, int a1, int a2, int a3, unsigned char a4) +{ + func_80057664(a0, 18, -1, (a1 & 0xff) ? a2 : 0, (a1 & 0xff) ? a3 : 0, 0, 0, 0, + a1 & 0xff, a4); +}