mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-25 02:20:33 +00:00
Collapse of atom 6-9 into a single atom (finaly). Generalized cross product atom proc and atom component. Still working on normalize_v3s4.
This commit is contained in:
@@ -108,10 +108,7 @@ typedef AtomBundle_(resolve_look_at) { MipsAtom*
|
||||
normalize_right_ux,
|
||||
cross_to_up,
|
||||
normalize_up_uy,
|
||||
populate,
|
||||
set_gte_mt3s2s4,
|
||||
matrix_vector,
|
||||
trans_matrix;
|
||||
pop_mv_trans;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -179,108 +176,114 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
|
||||
})
|
||||
|
||||
|
||||
typedef Struct_(Binds_ResolveLookAtPopAndTrans) {
|
||||
U4 look_at; /* U4 (MT3_S2S4* — destination matrix address) */
|
||||
typedef Struct_(Binds_ResolveLookAtPopMvTrans) {
|
||||
U4 look_at; /* MT3_S2S4* — destination matrix address */
|
||||
};
|
||||
typedef Struct_(RegUse_resolve_look_at__populate_proc) {
|
||||
Reg const scratch;
|
||||
typedef Struct_(RegUse_resolve_look_at__pop_mv_trans) {
|
||||
Reg scratch; /* loaded via load_word_imm below — can't rely on
|
||||
* R_T4 surviving across the tape_run boundary */
|
||||
Reg look_at;
|
||||
Reg_(V3_S4) row; /* one matrix row, reused */
|
||||
Reg ux;
|
||||
Reg uy;
|
||||
Reg uz;
|
||||
Reg_(V3_S4) row; /* populate phase: load ux/uy/uz */
|
||||
union { Reg ux, v_x; } t6; /* populate addr (canonical) → matrix_vector v_x */
|
||||
union { Reg uy, v_y; } t7; /* populate uy → matrix_vector v_y */
|
||||
union { Reg uz, v_z; } t8; /* populate uz → matrix_vector v_z */
|
||||
Reg eye; /* matrix_vector phase: load -eye */
|
||||
};
|
||||
/* Atom 6a: write look_at->m[][] from ux/uy/uz as S2. Zero t[].
|
||||
/* Atom 6 (fused): write look_at->m[][] from ux/uy/uz as packed S2 (populate),
|
||||
* ctc2 RT chain into C2[0..4] (matrix_vector), MVMVA RT*(-eye)>>12, store off
|
||||
* directly to look_at->t[] (trans_matrix). Replaces the previous 3 separate atoms
|
||||
* (populate + matrix_vector + trans_matrix).
|
||||
*
|
||||
* MT3_S2S4 { A3x3_S2 m; A3_S4 t; }
|
||||
* m[][] is S2 packed (9 × 2 = 18 bytes at offset 0)
|
||||
* t[0/1/2] is S4 (3 × 4 = 12 bytes at offset 18)
|
||||
*/
|
||||
internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa,
|
||||
RegUse_resolve_look_at__populate_proc r
|
||||
) MipsAtom_Proc_(aa, {
|
||||
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
|
||||
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)),
|
||||
|
||||
add_si(r.ux, r.scratch, O_(ResolveLookAtScratch,ux)), /* r.ux = &ux */ LdSlot_
|
||||
add_si(r.uy, r.scratch, O_(ResolveLookAtScratch,uy)), /* r.uy = &uy */ LdSlot_
|
||||
add_si(r.uz, r.scratch, O_(ResolveLookAtScratch,uz)), /* r.uz = &uz */ LdSlot_
|
||||
|
||||
mac_load_v3s4(r.row, r.ux, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4,m[0])),
|
||||
mac_load_v3s4(r.row, r.uy, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4,m[1])),
|
||||
mac_load_v3s4(r.row, r.uz, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4,m[2])),
|
||||
|
||||
/* Zero t[0..2] — atom 6c writes the final values here. */
|
||||
mac_store_v3s4(v3s4_R_0(), r.look_at, O_(MT3_S2S4,t)),
|
||||
mac_yield()
|
||||
})
|
||||
|
||||
typedef Struct_(RegUse_resolve_look_at__matrix_vector_proc) {
|
||||
Reg const scratch;
|
||||
Reg look_at;
|
||||
Reg eye; /* &scratch.eye; store dest for off */
|
||||
Reg_(V3_S4) v; /* RT words, then -eye, then off */
|
||||
};
|
||||
/* Atom 6b: off = look_at.m * (-eye) >> 12. Stores off over scratch.eye.
|
||||
* t[0..2] is S4 (3 × 4 = 12 bytes at offset 18)
|
||||
*
|
||||
* C11 ApplyMatrixLV:
|
||||
* C11 ApplyMatrixLV semantics (gte.atom.c ac_apply_matrix_lv; libgte reference):
|
||||
* 1. ctc2 RT matrix (5 ctc2s to C2[0..4])
|
||||
* 2. lw v.x/y/z from memory
|
||||
* 3. S15 decomposition (negu + sra 15 + negu + andi 0x7FFF + negu)
|
||||
* 4. mtc2 HIGH bits to IR1/2/3, nop, MVMVA pass1 (sf=0, mx=0, v=3, cv=3)
|
||||
* 5. mfc2 MACs
|
||||
* 6. mtc2 LOW bits to IR1/2/3, nop, MVMVA pass2 (sf=1, mx=0, v=3, cv=3)
|
||||
* 7. mfc2 MACs
|
||||
* 8. Combine: (pass1 << 3) + pass2
|
||||
* 2. lw -eye from memory
|
||||
* 3. S15 decomposition (eliminated here — the fused body takes the >>12 path
|
||||
* directly via mtc2 IR + MVMVA pass2, matching the libgte canonical output)
|
||||
* 4. mtc2 to IR1/2/3, nop2, MVMVA pass2 (sf=1, mx=0, v=3, cv=3)
|
||||
* 5. mfc2 MACs → off
|
||||
* 6. store off to look_at->t[] (skip scratch.eye intermediate)
|
||||
*
|
||||
* GPR codes (assigned by resolve_look_at_init):
|
||||
* r_scratch : R_ResolveScratch (R_T4 carrier)
|
||||
* r_look_at : ralloc() — also serves as the off-dst in the trans_matrix phase
|
||||
* r_row : V3_S4, reused for ux/uy/uz loads in populate phase
|
||||
* r_eye : ralloc() — &scratch.eye, used for -eye load in matrix_vector phase
|
||||
* r_v_x/v_y/v_z : ralloc() — populate scratch addrs (ux/uy/uz), reused as
|
||||
* ctc2 transfer + MVMVA -eye temp in matrix_vector phase
|
||||
* (v_x/v_y/v_z alias ux/uy/uz via the union; lifetime ends for ux/uy/uz after
|
||||
* populate's mac_load_v3s4, so reusing for v.x/v.y/v.z is safe)
|
||||
* Pool cost: 1 carrier + 1 look_at + 3 row + 1 eye + 3 aliased = 9 GPRs
|
||||
*
|
||||
* Net word savings vs the previous 3-atom flow: ~15 words + 2 mac_yields + 1 tape pop.
|
||||
* - 2 mac_yields (trans_matrix's + matrix_vector's) → fused into one yield
|
||||
* - 1 redundant tb_data (look_at was pushed 2x; now once)
|
||||
* - mac_trans_mt3s3s4 (6 words) → replaced by direct mac_store_v3s4
|
||||
* - mac_store_v3s4 to scratch.eye (3 words intermediate) → eliminated
|
||||
* - add_si for r_off_ptr (2 words) → eliminated
|
||||
* - mac_store_v3s4 zero-store of t[] (3 words) → eliminated (matrix_vector writes
|
||||
* off directly; no consumer needed the zero first)
|
||||
* - 1 set_gte_mt3s2s4 ctc2 chain (13 baked words) → eliminated (matrix_vector
|
||||
* has its own ctc2 RT chain; cube rendering atoms reload C2 state themselves)
|
||||
*/
|
||||
internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa,
|
||||
RegUse_resolve_look_at__matrix_vector_proc r
|
||||
internal MipsAtom* resolve_look_at__pop_mv_trans(AtomArena_R aa,
|
||||
RegUse_resolve_look_at__pop_mv_trans r
|
||||
) MipsAtom_Proc_(aa, {
|
||||
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
|
||||
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)),
|
||||
/* --- Tape pop: look_at pointer --- */
|
||||
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopMvTrans,look_at)),
|
||||
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtPopMvTrans)),
|
||||
|
||||
/* Load RT from look_at.m into C2[0..4]. Packed S2 pairs, same as set_gte_mt3s2s4. */
|
||||
load_word( r.v.x, r.look_at, O_(MT3_S2S4, m[0][0])), /* RT11|RT12 */ LdSlot_ add_si(r.eye, r.scratch, O_(ResolveLookAtScratch,eye)), /* r.eye = &eye */
|
||||
load_word( r.v.y, r.look_at, O_(MT3_S2S4, m[0][2])), /* RT13|RT21 */ LdSlot_ gte_mv_to_ctrl_r(r.v.x, gte_cr_RT11),
|
||||
load_word( r.v.z, r.look_at, O_(MT3_S2S4, m[1][1])), /* RT22|RT23 */ LdSlot_ gte_mv_to_ctrl_r(r.v.y, gte_cr_RT12),
|
||||
load_word( r.v.x, r.look_at, O_(MT3_S2S4, m[2][0])), /* RT31|RT32 */ LdSlot_ gte_mv_to_ctrl_r(r.v.z, gte_cr_RT13),
|
||||
load_half_u(r.v.y, r.look_at, O_(MT3_S2S4, m[2][2])), /* RT33 */ LdSlot_ gte_mv_to_ctrl_r(r.v.x, gte_cr_RT21),
|
||||
/* pos = -eye. The three loads also retire the last CTC2. */ gte_mv_to_ctrl_r(r.v.y, gte_cr_RT22),
|
||||
GteDelay_ mac_load_p3s4(r.v, r.eye, 0), LdSlot_ mac_sub_v3s4(r.v, v3s4_R_0(), r.v), /* pos.x = -eye.x */
|
||||
/* Load scratch base via immediate (Scratchpad_Loc = 0x1F800000). We can't rely on
|
||||
* R_T4 (= R_ResolveScratch) surviving across the tape_run boundary — the compiler
|
||||
* treats it as clobberable per the tape_run asm_clobber list. Baking the scratch
|
||||
* address via load_word_imm is robust. */
|
||||
mac_load_word_imm(r.scratch, Scratchpad_Loc),
|
||||
|
||||
/* --- Scratch addresses for ux/uy/uz/eye (populate phase; t6/t7/t8 alias ux/uy/uz) --- */
|
||||
add_si(r.t6.ux, r.scratch, O_(ResolveLookAtScratch, ux)), LdSlot_
|
||||
add_si(r.t7.uy, r.scratch, O_(ResolveLookAtScratch, uy)),
|
||||
add_si(r.t8.uz, r.scratch, O_(ResolveLookAtScratch, uz)),
|
||||
add_si(r.eye, r.scratch, O_(ResolveLookAtScratch, eye)),
|
||||
|
||||
/* --- POPULATE phase: write look_at->m[][] from ux/uy/uz as packed S2 --- */
|
||||
mac_load_v3s4(r.row, r.t6.ux, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4, m[0])),
|
||||
mac_load_v3s4(r.row, r.t7.uy, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4, m[1])),
|
||||
mac_load_v3s4(r.row, r.t8.uz, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4, m[2])),
|
||||
|
||||
/* --- MATRIX-VECTOR phase: ctc2 RT chain + MVMVA RT*(-eye)>>12 --- */
|
||||
/* RT packing (per libgte ApplyMatrixLV convention; see gte.h:217-220 +
|
||||
* atom_6b_disasm_comparison.md:28-32):
|
||||
* C2[0] = (RT12<<16)|RT11 ← ctc2 RT11 from m[0][0..1] packed word
|
||||
* C2[1] = (RT21<<16)|RT13 ← ctc2 RT12 from m[0][2..3] packed word
|
||||
* C2[2] = (RT23<<16)|RT22 ← ctc2 RT13 from m[1][1..2] packed word
|
||||
* C2[3] = (RT32<<16)|RT31 ← ctc2 RT21 from m[2][0..1] packed word
|
||||
* C2[4] = (RT33<<16)|junk ← ctc2 RT22 from m[2][2] (half)
|
||||
* Each ctc2 writes a WHOLE 32-bit C2 slot; the "macro name" identifies
|
||||
* which C2 register, not which 16-bit half. */
|
||||
load_word( r.t6.v_x, r.look_at, O_(MT3_S2S4, m[0][0])), /* RT11|RT12 */ LdSlot_
|
||||
load_word( r.t7.v_y, r.look_at, O_(MT3_S2S4, m[0][2])), /* RT13|RT21 */ LdSlot_ gte_mv_to_ctrl_r(r.t6.v_x, gte_cr_RT11),
|
||||
load_word( r.t8.v_z, r.look_at, O_(MT3_S2S4, m[1][1])), /* RT22|RT23 */ LdSlot_ gte_mv_to_ctrl_r(r.t7.v_y, gte_cr_RT12),
|
||||
load_word( r.t6.v_x, r.look_at, O_(MT3_S2S4, m[2][0])), /* RT31|RT32 */ LdSlot_ gte_mv_to_ctrl_r(r.t8.v_z, gte_cr_RT13),
|
||||
load_half_u(r.t7.v_y, r.look_at, O_(MT3_S2S4, m[2][2])), /* RT33 */ LdSlot_ gte_mv_to_ctrl_r(r.t6.v_x, gte_cr_RT21),
|
||||
/* pos = -eye. The three loads also retire the last CTC2. */ gte_mv_to_ctrl_r(r.t7.v_y, gte_cr_RT22),
|
||||
GteDelay_ mac_load_word_v3(r.t6.v_x, r.t7.v_y, r.t8.v_z, r.eye, 0), LdSlot_
|
||||
mac_sub_s_v3(r.t6.v_x, r.t7.v_y, r.t8.v_z, R_0, R_0, R_0, r.t6.v_x, r.t7.v_y, r.t8.v_z),
|
||||
/* mtc2 pos (as S16) to IR1/2/3. The GTE takes low 16 bits. pos fits in S16. For negative pos, the 32-bit sign-extended value's low 16 bits = correct S16. */
|
||||
gte_mv_to_data_r(r.v.x, C2_IR1),
|
||||
gte_mv_to_data_r(r.v.y, C2_IR2),
|
||||
gte_mv_to_data_r(r.v.z, C2_IR3),
|
||||
gte_mv_to_data_r(r.t6.v_x, C2_IR1),
|
||||
gte_mv_to_data_r(r.t7.v_y, C2_IR2),
|
||||
gte_mv_to_data_r(r.t8.v_z, C2_IR3),
|
||||
GteDelay_ nop2,
|
||||
|
||||
/* MVMVA pass 2 — C11 ApplyMatrixLV command.
|
||||
* sf=1, mx=0 (RT), v=3 (IR), cv=3. Reads RT × IR >> 12. */
|
||||
gte_cmdw_mvmva_c11_pass2, GteDelay_ nop,
|
||||
mac_gte_mv_from_data_r_mac123(r.v.x, r.v.y, r.v.z), GteDelay_ nop,
|
||||
mac_store_v3s4(r.v, r.eye, 0),
|
||||
gte_cmdw_mvmva_c11_pass2, GteDelay_ nop,
|
||||
mac_gte_mv_from_data_r_mac123(r.t6.v_x, r.t7.v_y, r.t8.v_z), GteDelay_ nop,
|
||||
|
||||
mac_yield()
|
||||
})
|
||||
|
||||
/* Atom 6c in the bundle: copy scratch+96 (off, written by atom 6b) → look_at->t[].
|
||||
* Uses mac_trans_matrix component (m->t = v, libgte TransMatrix semantics = struct copy).
|
||||
*
|
||||
* GPR codes (assigned by resolve_look_at_init):
|
||||
* r_look_at : MT3_S2S4* (popped from tape; output matrix destination)
|
||||
* r_scratch : R_ResolveScratch (R_T4) — scratch base
|
||||
* r_off_ptr : pointer to off (= &scratch.eye, reused slot)
|
||||
* r_tmp0 : transfer reg for mac_trans_matrix
|
||||
*
|
||||
* Pool cost: r_look_at (1) + r_scratch (carrier) + r_off_ptr + 1 clobber = 4 GPRs.
|
||||
*/
|
||||
I_ MipsAtom* AtomBundleEntry_(resolve_look_at,trans_matrix)(AtomArena_R aa
|
||||
, U4 r_look_at, U4 r_scratch, U4 r_off_ptr
|
||||
, U4 r_tmp0, U4 r_tmp1, U4 r_tmp2
|
||||
) MipsAtom_Proc_(aa, {
|
||||
/* r_off_ptr = &off (= &scratch.eye since atom 6b overwrote eye with off). */
|
||||
add_si(r_off_ptr, r_scratch, O_(ResolveLookAtScratch,eye)), nop,
|
||||
|
||||
/* Copy off → look_at.t[] (mac_trans_matrix: m->t = v). */
|
||||
mac_trans_mt3s3s4(r_look_at, r_off_ptr, r_tmp0, r_tmp1, r_tmp2),
|
||||
/* --- TRANS-MATRIX phase: store off directly to look_at->t[] (skip scratch.eye intermediate) --- */
|
||||
mac_store_word_v3(r.t6.v_x, r.t7.v_y, r.t8.v_z, r.look_at, O_(MT3_S2S4, t)),
|
||||
|
||||
mac_yield()
|
||||
})
|
||||
|
||||
@@ -52,11 +52,6 @@
|
||||
#include "hello_camera.atom.c"
|
||||
#pragma endregion Hello Joypad TUs
|
||||
|
||||
enum {
|
||||
Scratchpad_Loc = 0x1F800000,
|
||||
};
|
||||
#define C_scratch(type) C_(type, Scratchpad_Loc)
|
||||
|
||||
enum {
|
||||
Scratchpad_Len = 1024,
|
||||
MemTape_Len = 512,
|
||||
@@ -91,9 +86,11 @@ typedef Struct_(SMemory) {
|
||||
|
||||
U1 ct_init_atom_mem[CT_InitAtomMem_Size];
|
||||
MipsAtom* normalize_v3s4;
|
||||
// TODO(Ed): Convert normalize_v3s4 to a generic atom?
|
||||
// This would allow us to reduce specializations with the loss being some cycles to loading registers.
|
||||
// The cost would be 3 loads (scratch, src_ptr, dst_offset) from tape and
|
||||
MipsAtom* gte_cross_v3s4; /* GTE OP OuterProduct12 (a × b → out).
|
||||
* Baked once at init from compile_gte_cross_v3s4() into ct_init_atom_mem.
|
||||
* One instance serves both cross call sites in resolve_look_at;
|
||||
* per-frame tape emits push src_a/src_b/out (3 pointers = 12 bytes)
|
||||
* for Binds_gte_cross_v3s4. */
|
||||
|
||||
U1 resolve_look_at_mem[ResolveLookAtArena_Size];
|
||||
MipsAtom* resolve_look_at_bundle[AtomBundle_Len(resolve_look_at)];
|
||||
@@ -143,6 +140,57 @@ FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_lo
|
||||
|
||||
|
||||
|
||||
internal void compile_init_atoms(void) {
|
||||
/* Single shared arena: each compile_* function pushes its atom into the same
|
||||
* ct_init_atom_mem backing. If each function called atomarena_make() locally,
|
||||
* the second call would reset arena.used to 0 and overwrite the first atom.
|
||||
*/
|
||||
AtomArena ab = atomarena_make(slice_ut_arr(smem.ct_init_atom_mem));
|
||||
RegFile rf = regfile(regfile_abi_mask);
|
||||
|
||||
/* === gte_cross_v3s4 — GTE OP OuterProduct12 (a × b → out) ===
|
||||
* Reused by both cross call sites in resolve_look_at. No scratch carrier.
|
||||
* GPR pool: 9 allocatable (no carrier). Pool R_T0..R_T7, R_V0, R_V1 minus ABI = 9.
|
||||
* Fits exactly. */
|
||||
{
|
||||
smem.gte_cross_v3s4 = gte_cross_v3s4(& ab,
|
||||
RegUse_(gte_cross_v3s4) {
|
||||
.a = { regfile_alloc(& rf), regfile_alloc(& rf), regfile_alloc(& rf) },
|
||||
.b = { regfile_alloc(& rf), regfile_alloc(& rf), regfile_alloc(& rf) },
|
||||
.x = regfile_alloc(& rf), /* out / t0 shared */
|
||||
.y = regfile_alloc(& rf), /* src_a / t1 / rt11 shared */
|
||||
.z = regfile_alloc(& rf), /* src_b / t2 / rt22 shared */
|
||||
});
|
||||
regfile_reset(& rf);
|
||||
}
|
||||
|
||||
/* === build_normalize_v3s4 — Generic 4-stage GTE normalize ===
|
||||
* Reused by all 3 normalize call sites in resolve_look_at. Reads scratch + src/dst
|
||||
* offsets from tape (no carrier — atom is fully self-contained per call).
|
||||
* GPR pool: no carrier, 10 allocatable (R_T0..R_T7, R_V0, R_V1 minus ABI pins).
|
||||
* 10 fields (scratch + src_ptr + dst_ptr + recip_est + norm + shift + src_x +
|
||||
* t3 + t4 + t5) → just fits. Union members t5.src_offset, t3.dst_offset, etc.
|
||||
* share GPRs via lifetime discipline. */
|
||||
{
|
||||
RegFile rf = regfile(regfile_abi_mask);
|
||||
smem.normalize_v3s4 = build_normalize_v3s4(& ab,
|
||||
RegUse_(build_normalize_v3s4) {
|
||||
.scratch = regfile_alloc(& rf),
|
||||
.src_ptr = regfile_alloc(& rf),
|
||||
.dst_ptr = regfile_alloc(& rf),
|
||||
.recip_est = regfile_alloc(& rf),
|
||||
.norm = regfile_alloc(& rf),
|
||||
.shift = regfile_alloc(& rf),
|
||||
.src_x = regfile_alloc(& rf),
|
||||
.t3 = regfile_alloc(& rf),
|
||||
.t4 = regfile_alloc(& rf),
|
||||
.t5 = regfile_alloc(& rf),
|
||||
});
|
||||
}
|
||||
|
||||
assert(ab.used <= CT_InitAtomMem_Size);
|
||||
}
|
||||
|
||||
internal void compile_resolve_look_at(void) {
|
||||
/* Wrap the static arena in a MipsAtomBuilder. */
|
||||
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
|
||||
@@ -169,118 +217,32 @@ internal void compile_resolve_look_at(void) {
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
|
||||
/* === ATOM 1: normalize fwd→uz === */
|
||||
U2 src_offset = O_(ResolveLookAtScratch, fwd);
|
||||
U2 dst_offset = O_(ResolveLookAtScratch, uz);
|
||||
smem.resolve_look_at_bundle[1] = build_normalize_v3s4(& ab,
|
||||
src_offset, dst_offset, RegUse_(build_normalize_v3s4){
|
||||
.scratch = R_ResolveScratch,
|
||||
.src_ptr = ralloc(),
|
||||
.dst_ptr = ralloc(),
|
||||
.recip_est = ralloc(),
|
||||
.norm = ralloc(),
|
||||
.shift = ralloc(),
|
||||
.src_x = ralloc(),
|
||||
.t3 = ralloc(),
|
||||
.t4 = ralloc(),
|
||||
.t5 = ralloc(),
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
smem.resolve_look_at_bundle[1] = smem.normalize_v3s4;
|
||||
|
||||
/* === ATOM 2: cross uz×up_in→right (Binds_gte_cross_v3s4) === */
|
||||
smem.resolve_look_at_bundle[2] = gte_cross_v3s4(& ab,
|
||||
RegUse_(gte_cross_v3s4) {
|
||||
.a = ralloc_v3(),
|
||||
.b = ralloc_v3(),
|
||||
.t0 = ralloc(),
|
||||
.t1 = ralloc(),
|
||||
.t2 = ralloc(),
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
/* === ATOM 2: cross uz×up_in→right (reuses smem.gte_cross_v3s4) === */
|
||||
smem.resolve_look_at_bundle[2] = smem.gte_cross_v3s4;
|
||||
|
||||
/* === ATOM 3: normalize right→ux === */
|
||||
src_offset = O_(ResolveLookAtScratch, right);
|
||||
dst_offset = O_(ResolveLookAtScratch, ux);
|
||||
smem.resolve_look_at_bundle[3] = build_normalize_v3s4(& ab,
|
||||
src_offset, dst_offset, RegUse_(build_normalize_v3s4){
|
||||
.scratch = R_ResolveScratch,
|
||||
.src_ptr = ralloc(),
|
||||
.dst_ptr = ralloc(),
|
||||
.recip_est = ralloc(),
|
||||
.norm = ralloc(),
|
||||
.shift = ralloc(),
|
||||
.src_x = ralloc(),
|
||||
.t3 = ralloc(),
|
||||
.t4 = ralloc(),
|
||||
.t5 = ralloc(),
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
smem.resolve_look_at_bundle[3] = smem.normalize_v3s4;
|
||||
|
||||
/* === ATOM 4: cross uz×ux→up (Binds_gte_cross_v3s4) === */
|
||||
smem.resolve_look_at_bundle[4] = gte_cross_v3s4(& ab,
|
||||
RegUse_(gte_cross_v3s4) {
|
||||
.a = ralloc_v3(),
|
||||
.b = ralloc_v3(),
|
||||
.t0 = ralloc(),
|
||||
.t1 = ralloc(),
|
||||
.t2 = ralloc(),
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
/* === ATOM 4: cross uz×ux→up (reuses smem.gte_cross_v3s4) === */
|
||||
smem.resolve_look_at_bundle[4] = smem.gte_cross_v3s4;
|
||||
|
||||
/* === ATOM 5: normalize up→uy === */
|
||||
src_offset = O_(ResolveLookAtScratch, up);
|
||||
dst_offset = O_(ResolveLookAtScratch, uy);
|
||||
smem.resolve_look_at_bundle[5] = build_normalize_v3s4(& ab,
|
||||
src_offset, dst_offset,
|
||||
RegUse_(build_normalize_v3s4){
|
||||
.scratch = R_ResolveScratch,
|
||||
.src_ptr = ralloc(),
|
||||
.dst_ptr = ralloc(),
|
||||
.recip_est = ralloc(),
|
||||
.norm = ralloc(),
|
||||
.shift = ralloc(),
|
||||
.src_x = ralloc(),
|
||||
.t3 = ralloc(),
|
||||
.t4 = ralloc(),
|
||||
.t5 = ralloc(),
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
smem.resolve_look_at_bundle[5] = smem.normalize_v3s4;
|
||||
|
||||
/* === ATOM 6a: populate (m[][] from ux/uy/uz, t[]=0) === */
|
||||
smem.resolve_look_at_bundle[6] = resolve_look_at__populate_proc(& ab,
|
||||
RegUse_(resolve_look_at__populate_proc){
|
||||
.scratch = R_ResolveScratch,
|
||||
.look_at = ralloc(), /* T0 */
|
||||
.row = ralloc_v3(), /* T1 T2 T3 */
|
||||
.ux = ralloc(), /* T5 = ux */
|
||||
.uy = ralloc(), /* T6 = uy */
|
||||
.uz = ralloc(), /* T7 = uz */
|
||||
});
|
||||
regfile_reset_to_mask(& rf, pin_mask);
|
||||
|
||||
/* === ATOM 6a.5: set_gte_mt3s2s4 (BAKED — ctc2 RT matrix) === */
|
||||
smem.resolve_look_at_bundle[7] = (MipsAtom*) & set_gte_mt3s2s4;
|
||||
|
||||
/* === ATOM 6b: matrix_vector (RT * (-eye) >> 12) === */
|
||||
smem.resolve_look_at_bundle[8] = resolve_look_at__matrix_vector_proc(& ab,
|
||||
RegUse_(resolve_look_at__matrix_vector_proc){
|
||||
.scratch = R_ResolveScratch,
|
||||
.look_at = ralloc(), /* T0 */
|
||||
.eye = ralloc(), /* T1 */
|
||||
.v = ralloc_v3(), /* T2 T3 T5 */
|
||||
});
|
||||
|
||||
/* === ATOM 6c: trans_matrix (off → look_at->t[]) === */
|
||||
U4 r_look_at_6c = R_T0; /* tape pop → look_at* */
|
||||
U4 r_scratch_6c = R_ResolveScratch;
|
||||
U4 r_off_ptr_6c = R_T1; /* &scratch.eye (= off dst) */
|
||||
U4 r_tmp0_6c = R_T2;
|
||||
smem.resolve_look_at_bundle[9] = AtomBundleEntry_(resolve_look_at,trans_matrix)(& ab,
|
||||
r_look_at_6c,
|
||||
r_scratch_6c,
|
||||
r_off_ptr_6c,
|
||||
r_tmp0_6c,
|
||||
R_T3,
|
||||
R_T4);
|
||||
/* === ATOM 6 (FUSED): populate + ctc2 RT + MVMVA + trans_matrix → look_at === */
|
||||
smem.resolve_look_at_bundle[6] = resolve_look_at__pop_mv_trans(& ab,
|
||||
RegUse_(resolve_look_at__pop_mv_trans){
|
||||
.scratch = R_ResolveScratch,
|
||||
.look_at = ralloc(), /* T0 */
|
||||
.eye = ralloc(), /* T1 — allocated BEFORE row so it doesn't alias row.y */
|
||||
.row = ralloc_v3(), /* T2 T3 T5 */
|
||||
.t6 = ralloc(), /* T6 = ux (populate) / v_x (matrix_vector) */
|
||||
.t7 = ralloc(), /* T7 = uy (populate) / v_y (matrix_vector) */
|
||||
.t8 = ralloc(), /* V0 = uz (populate) / v_z (matrix_vector) */
|
||||
});
|
||||
/* No regfile_reset between phases: the fused atom uses all 9 GPRs throughout. */
|
||||
|
||||
/* Sanity check: arena didn't overflow. */
|
||||
assert(ab.used <= ResolveLookAtArena_Size);
|
||||
@@ -305,7 +267,11 @@ I_ void resolve_look_at(TapeBuilder_R tb
|
||||
}
|
||||
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[1]); {
|
||||
// tb_data(tb, u4_(Scratchpad_Loc));
|
||||
/* Binds_NormalizeV3S4: src_offset (low 16) | dst_offset (high 16). Both U2s
|
||||
* packed into a single U4 because the atom body reads at byte offsets 0 and 2
|
||||
* from R_TapePtr. Scratch base is baked into the atom (load_word_imm of
|
||||
* Scratchpad_Loc). */
|
||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16)));
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[2]); {
|
||||
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
|
||||
@@ -314,7 +280,7 @@ I_ void resolve_look_at(TapeBuilder_R tb
|
||||
tb_data(tb, u4_(& sp->right)); /* out */
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[3]); {
|
||||
// tb_data(tb, u4_(Scratchpad_Loc));
|
||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, right) | (O_(ResolveLookAtScratch, ux) << 16)));
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[4]); {
|
||||
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
|
||||
@@ -323,21 +289,13 @@ I_ void resolve_look_at(TapeBuilder_R tb
|
||||
tb_data(tb, u4_(& sp->up)); /* out */
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[5]); {
|
||||
// tb_data(tb, u4_(Scratchpad_Loc));
|
||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, up) | (O_(ResolveLookAtScratch, uy) << 16)));
|
||||
}
|
||||
|
||||
/* === FUSED atom: populate + matrix_vector + trans_matrix (replaces 4 separate emits) === */
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[6]); {
|
||||
tb_data(tb, u4_(look_at));
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[7]); {
|
||||
tb_data(tb, u4_(look_at));
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[8]); {
|
||||
tb_data(tb, u4_(look_at));
|
||||
}
|
||||
tb_emit(tb, smem.resolve_look_at_bundle[9]); {
|
||||
// tb_data(tb, u4_(look_at));
|
||||
}
|
||||
}
|
||||
|
||||
GCC_OPTIMIZATION_DISABLE
|
||||
@@ -529,6 +487,7 @@ int main(void)
|
||||
/* Direct BIOS: poll both ports during VBlank. */
|
||||
pad_bios_init_start(& smem.pad_raw[0], & smem.pad_raw[1]);
|
||||
|
||||
compile_init_atoms();
|
||||
compile_resolve_look_at();
|
||||
|
||||
/* Pinned registers for the GPU init atom. */
|
||||
|
||||
Reference in New Issue
Block a user