From d9b9241e2cc95ff5bbc020fc119464d635e14d8b Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 15 Aug 2026 19:53:08 -0400 Subject: [PATCH] resolve_look_at__cross_uz_ux_to_up_proc reviewed --- code/duffle/gen/macs.h | 4 +- code/duffle/gen/offsets.h | 4 +- code/duffle/gp.h | 1 + code/duffle/gte.atom.c | 12 ++-- code/duffle/gte.h | 2 +- code/hello_camera/gen/offsets.h | 2 +- code/hello_camera/hello_camera.atom.c | 90 ++++++++++++--------------- code/hello_camera/hello_camera.c | 19 +++--- 8 files changed, 64 insertions(+), 70 deletions(-) diff --git a/code/duffle/gen/macs.h b/code/duffle/gen/macs.h index 9829c34..e36c41a 100644 --- a/code/duffle/gen/macs.h +++ b/code/duffle/gen/macs.h @@ -250,8 +250,8 @@ WORD_COUNT(mac_lzcr_round_even_half_shift, 5) , gte_mv_to_data_r(to_ir1, C2_IR1) /* IR1 = src.x (preserved in r_tmp — r_mac2_scratch was clobbered to MAC2 in stage 1.5) */ \ , gte_mv_to_data_r(to_ir2, C2_IR2) \ , gte_mv_to_data_r(to_ir3, C2_IR3) /* IR3 = src.z (reloaded) */ \ -, DmaSlot_ nop_slot1 \ -, DmaSlot_ nop_slot2 \ +, GteDelay_ nop_slot1 \ +, GteDelay_ nop_slot2 \ , gte_cmdw_gpf \ , gte_mv_from_data_r(fr_mac1, C2_MAC1) \ , gte_mv_from_data_r(fr_mac2, C2_MAC2) \ diff --git a/code/duffle/gen/offsets.h b/code/duffle/gen/offsets.h index 8da9966..5889809 100644 --- a/code/duffle/gen/offsets.h +++ b/code/duffle/gen/offsets.h @@ -25,7 +25,7 @@ #pragma region duffle -// --- atom: example_atom (10 words) --- +// --- atom: example_atom_proc (10 words) --- #define _atom_offset_example_atom_proc_skip 2 @@ -33,7 +33,7 @@ enum { atom_offset_example_atom_proc_skip = _atom_offset_example_atom_proc_skip, }; -// --- atom: normalize_v3s4 (47 words) --- +// --- atom: normalize_v3s4_proc (61 words) --- #define _atom_offset_aligned_done_srav_path 3 #define _atom_offset_srav_path_aligned_done 4 diff --git a/code/duffle/gp.h b/code/duffle/gp.h index 25bfed1..05138ac 100644 --- a/code/duffle/gp.h +++ b/code/duffle/gp.h @@ -68,6 +68,7 @@ enum { #define gp0_send(word) (HW_GP0[0] = (word)) #define gp1_send(word) (HW_GP1[0] = (word)) +#define DmaSlot_ // Annotate an instruction as filling a CPU <-> Command DMA delay slot/s /* ============================================================================ * GP0 command byte constants + Layer 1 (GPU bitfield shifts) diff --git a/code/duffle/gte.atom.c b/code/duffle/gte.atom.c index 69226f0..a9743c5 100644 --- a/code/duffle/gte.atom.c +++ b/code/duffle/gte.atom.c @@ -150,8 +150,8 @@ MipsAtomComp_Proc_(ab, { gte_mv_to_data_r(to_ir1, C2_IR1), /* IR1 = src.x (preserved in r_tmp — r_mac2_scratch was clobbered to MAC2 in stage 1.5) */ gte_mv_to_data_r(to_ir2, C2_IR2), gte_mv_to_data_r(to_ir3, C2_IR3), /* IR3 = src.z (reloaded) */ - DmaSlot_ nop_slot1, - DmaSlot_ nop_slot2, + GteDelay_ nop_slot1, + GteDelay_ nop_slot2, gte_cmdw_gpf, gte_mv_from_data_r(fr_mac1, C2_MAC1), gte_mv_from_data_r(fr_mac2, C2_MAC2), @@ -293,8 +293,8 @@ MipsAtom_Proc_(aa, { mac_gte_mv_from_data_r_mac123(r.t3.mac1_scratch, r.t4.mac2_scratch, r.norm), LdSlot_ nop, add_u_self( r.norm, r.t3.mac1_scratch), add_u_self( r.norm, r.t4.mac2_scratch), - gte_mv_to_data_r( r.norm, C2_LZCS), DmaSlot_ nop2, - gte_mv_from_data_r(r.shift, C2_LZCR), DmaSlot_ nop, + gte_mv_to_data_r( r.norm, C2_LZCS), GteDelay_ nop2, + gte_mv_from_data_r(r.shift, C2_LZCR), GteDelay_ nop, /* Stage 3: round LZCR to even, compute half-shift, align |v|² to bit 24. * r_norm holds |v|² sum; r_shift holds the LZCR count from mfc2. @@ -328,8 +328,8 @@ MipsAtom_Proc_(aa, { r.recip_est, r.t5.src_z, /* IR3 = src.z (reloaded) */ r.t4.mac2_scratch, r.recip_est, r.t5.src_z, - DmaSlot_ add_si(r.dst_ptr, r.scratch, dst_offset), // pre-laoding destination to register here. - DmaSlot_ nop + GteDelay_ add_si(r.dst_ptr, r.scratch, dst_offset), // pre-laoding destination to register here. + GteDelay_ nop ), /* sra by r_shift = (31-LZCR)/2 (saved before sqrtbl lookup) */ mac_shift_aright_var_v3_self(r.t4.mac2_scratch, r.recip_est, r.t5.src_z, r.shift), diff --git a/code/duffle/gte.h b/code/duffle/gte.h index 7aedc1b..6e3899d 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -310,7 +310,7 @@ enum { _C2_TX_SUBS_ = 0 #define gte_mv_from_ctrl_r(rt, rd) enc_gte_tx(sub_cfc2, (rt), (rd)) /* Copy From ctrl reg */ #define gte_mv_to_data_r(rt, rd) enc_gte_tx(sub_mtc2, (rt), (rd)) /* Move To data reg */ #define gte_mv_to_ctrl_r(rt, rd) enc_gte_tx(sub_ctc2, (rt), (rd)) /* Copy To ctrl reg */ -#define DmaSlot_ // Annotate an instruction as filling a CPU <-> GTE DMA delay slot/s +#define GteDelay_ // Annotate an instruction as filling a CPU <-> GTE DMA delay slot/s /* COP2 Data Load (lwc2): `lwc2 rt, off(rs)` * Layout: [op_lwc2:6][rs:5][rt:5][imm:16] diff --git a/code/hello_camera/gen/offsets.h b/code/hello_camera/gen/offsets.h index 7dd00f1..2e95a28 100644 --- a/code/hello_camera/gen/offsets.h +++ b/code/hello_camera/gen/offsets.h @@ -26,7 +26,7 @@ enum { atom_offset_end_low_exit_stick = _atom_offset_end_low_exit_stick, }; -// --- atom: pad_input_cam (42 words) --- +// --- atom: pad_input_cam (40 words) --- #define _atom_offset_left_x_exit_left_x 3 #define _atom_offset_right_x_exit_right_x 3 diff --git a/code/hello_camera/hello_camera.atom.c b/code/hello_camera/hello_camera.atom.c index 668525c..8d23d1c 100644 --- a/code/hello_camera/hello_camera.atom.c +++ b/code/hello_camera/hello_camera.atom.c @@ -220,13 +220,13 @@ internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa, /* Load uz into the RT diagonal. */ gte_mv_to_ctrl_r(r.a, gte_cr_RT11), /* D1 = RT11 = uz.x (low 16 of $0, sign-extended by OP). */ - DmaSlot_ nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */ + GteDelay_ nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */ /* Load up_in into IR (the second operand for OP). */ gte_mv_to_data_r(r.d, C2_IR1), /* IR1 = up_in.x */ gte_mv_to_data_r(R_AT, C2_IR2), /* IR2 = up_in.y */ gte_mv_to_data_r(r.t0, C2_IR3), /* IR3 = up_in.z */ - DmaSlot_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ + GteDelay_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ gte_cmdw_cross, /* OP: MAC1/2/3 = uz × up_in * MAC1 = IR3*D2 - IR2*D3 = up_in.z*uz.y.high - up_in.y*uz.z.high @@ -243,7 +243,7 @@ internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa, /* mfc2 MAC1/2/3 → r_a/r_b/r_c (out.x/y/z). */ mac_gte_mv_from_data_r_mac123(r.a, r.b, r.c), - DmaSlot_ nop, /* MFC2 retirement */ + GteDelay_ nop, /* MFC2 retirement */ /* Right-shift MAC by 12 to convert from GTE's S12.20 fixed-point scale back to libpsyx OuterProduct12 convention (S12.0, fp_one=4096=1<<12). * Without this, MAC values (~16M for unit-vector cross products) overflow the GTE's 16-bit IR registers when atom 3 normalizes via mtc2. */ @@ -254,74 +254,66 @@ internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa, mac_yield() }) +typedef Struct_(RegUse_resolve_look_at__cross_uz_ux_to_up_proc) { + Reg const scratch; /* pinned T4 */ + Reg_(V3_S4) a; /* uz components, then MAC / out */ + Reg_(V3_S4) b; /* ux components */ + union { Reg t0, up; }; /* &up, dedicated */ + union { Reg t1, uz, rt11; }; /* &uz, then RT11 save */ + union { Reg t2, ux, rt22; }; /* &ux, then RT22 save */ +}; /* Atom 4: cross uz × ux → up. */ -internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa, U4 r_scratch - , U4 r_a, U4 r_b, U4 r_c /* load a.x/y/z; result out.x/y/z */ - , U4 r_d /* load b.x */ - , U4 r_f, U4 r_g, U4 r_h /* r_f = &up (out ptr), r_g = &uz, r_h = &ux */ +internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa, + RegUse_resolve_look_at__cross_uz_ux_to_up_proc r ) MipsAtom_Proc_(aa, { - /* Compute the three scratch pointers from r_scratch. */ - add_si(r_g, r_scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */ - add_si(r_h, r_scratch, O_(ResolveLookAtScratch,ux)), /* r_h = &ux */ - add_si(r_f, r_scratch, O_(ResolveLookAtScratch,up)), /* r_f = &up (out) */ + add_si(r.uz, r.scratch, O_(ResolveLookAtScratch,uz)), /* r.uz = &uz */ + add_si(r.ux, r.scratch, O_(ResolveLookAtScratch,ux)), /* r.ux = &ux */ + add_si(r.up, r.scratch, O_(ResolveLookAtScratch,up)), /* r.up = &up (out) */ nop, - /* Load a (uz).x/y/z into r_a/r_b/r_c. */ - load_word(r_a, r_g, O_(V3_S4,x)), - load_word(r_b, r_g, O_(V3_S4,y)), - load_word(r_c, r_g, O_(V3_S4,z)), - nop, + /* Load a (uz).x/y/z into r.a. */ + mac_load_v3s4(r.a, r.uz, 0), LdSlot_ nop, - /* Load b (ux).x/y/z into r_d + R_AT/R_V0. */ - load_word(r_d, r_h, O_(V3_S4,x)), - load_word(R_AT, r_h, O_(V3_S4,y)), - load_word(R_V0, r_h, O_(V3_S4,z)), - nop, + /* Load b (ux).x/y/z into r.b. */ + mac_load_v3s4(r.b, r.ux, 0), LdSlot_ /* taken by gte_mv_from_ctrl_r */ /* OP reads D1/D2/D3 from RT11/RT22/RT33 ($0/$2/$4), not V0/V1/V2. - * Mirror atom 1: cfc2 RT save, ctc2 RT diagonal from uz, mtc2 IR from ux, - * ctc2 RT restore. */ + * Mirror atom 1: cfc2 RT save, ctc2 RT diagonal from uz, mtc2 IR from ux, ctc2 RT restore. */ - /* Save the two RT control-register slots OP will clobber (reusing - * r_g/r_h — they're no longer needed as scratch pointers). */ - gte_mv_from_ctrl_r(r_g, gte_cr_RT11), /* r_g = C2 $0 (RT11|RT12) */ - gte_mv_from_ctrl_r(r_h, gte_cr_RT22), /* r_h = C2 $4 (RT22|RT33) */ + /* Save the two RT control-register slots OP will clobber (reusing r.uz/r.ux — they're no longer needed as scratch pointers). */ + gte_mv_from_ctrl_r(r.rt11, gte_cr_RT11), /* r.rt11 = C2 $0 (RT11|RT12) */ + gte_mv_from_ctrl_r(r.rt22, gte_cr_RT22), /* r.rt22 = C2 $4 (RT22|RT33) */ /* Load uz into the RT diagonal — same packing as atom 1. * OP reads D1 = RT11 from $0.low, D2 = RT22 from $2.high, D3 = RT33 from $4.high. * RT22 is shared between $2.high and $4.low — the ctc2 sequence to $2 then $4 - * sets RT22 to uz.y.high (via $2), then to uz.z.low (via $4). OP reads - * RT22 from $2.high which the second ctc2 doesn't touch, so D2 stays uz.y.high. + * sets RT22 to uz.y.high (via $2), then to uz.z.low (via $4). + * OP reads RT22 from $2.high which the second ctc2 doesn't touch, so D2 stays uz.y.high. * (This is libpsyx OuterProduct12 convention EXACTLY.) */ - gte_mv_to_ctrl_r(r_b, gte_cr_RT13), /* $2 = uz.y. RT13=uz.y.low, RT22=uz.y.high. */ - gte_mv_to_ctrl_r(r_c, gte_cr_RT22), /* $4 = uz.z. RT22=uz.z.low, RT33=uz.z.high. */ - gte_mv_to_ctrl_r(r_a, gte_cr_RT11), /* $0 = uz.x. RT11=uz.x. */ - nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */ + gte_mv_to_ctrl_r(r.a.y, gte_cr_RT13), /* $2 = uz.y. RT13=uz.y.low, RT22=uz.y.high. */ + gte_mv_to_ctrl_r(r.a.z, gte_cr_RT22), /* $4 = uz.z. RT22=uz.z.low, RT33=uz.z.high. */ + gte_mv_to_ctrl_r(r.a.x, gte_cr_RT11), /* $0 = uz.x. RT11=uz.x. */ + GteDelay_ nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */ /* Load ux into the IR registers (the second operand for OP). */ - gte_mv_to_data_r(r_d, C2_IR1), /* IR1 = ux.x */ - gte_mv_to_data_r(R_AT, C2_IR2), /* IR2 = ux.y */ - gte_mv_to_data_r(R_V0, C2_IR3), /* IR3 = ux.z */ - nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ + gte_mv_to_data_r(r.b.x, C2_IR1), /* IR1 = ux.x */ + gte_mv_to_data_r(r.b.y, C2_IR2), /* IR2 = ux.y */ + gte_mv_to_data_r(r.b.z, C2_IR3), /* IR3 = ux.z */ + GteDelay_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ gte_cmdw_outer_product, /* Restore the RT slots we clobbered. */ - gte_mv_to_ctrl_r(r_g, gte_cr_RT11), /* restore C2 $0 (RT11|RT12) */ - gte_mv_to_ctrl_r(r_h, gte_cr_RT22), /* restore C2 $4 (RT22|RT33) */ + gte_mv_to_ctrl_r(r.rt11, gte_cr_RT11), /* restore C2 $0 (RT11|RT12) */ + gte_mv_to_ctrl_r(r.rt22, gte_cr_RT22), /* restore C2 $4 (RT22|RT33) */ + + mac_gte_mv_from_data_r_mac123(r.a.x, r.a.y, r.a.z), + GteDelay_ nop, - gte_mv_from_data_r(r_a, C2_MAC1), - gte_mv_from_data_r(r_b, C2_MAC2), - gte_mv_from_data_r(r_c, C2_MAC3), - nop, /* Right-shift MAC by 12 to convert from GTE's S12.20 scale back to libpsyx * OuterProduct12 convention (S12.0, fp_one=4096). See atom 1 for rationale. */ - shift_aright(r_a, r_a, 12), - shift_aright(r_b, r_b, 12), - shift_aright(r_c, r_c, 12), - store_word(r_a, r_f, O_(V3_S4,x)), - store_word(r_b, r_f, O_(V3_S4,y)), - store_word(r_c, r_f, O_(V3_S4,z)), + mac_shift_aright_v3_self(r.a.x, r.a.y, r.a.z, 12), + mac_store_v3s4(r.a, r.up, 0), mac_yield() }) diff --git a/code/hello_camera/hello_camera.c b/code/hello_camera/hello_camera.c index 5b7584b..d3a8470 100644 --- a/code/hello_camera/hello_camera.c +++ b/code/hello_camera/hello_camera.c @@ -150,6 +150,7 @@ internal void resolve_look_at_init(void) { U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch); RegFile rf = regfile(pin_mask); #define ralloc() regfile_alloc(& rf) +#define ralloc_v3() { ralloc(), ralloc(), ralloc() } smem.resolve_look_at_atom_addrs[0] = resolve_look_at__input_and_sub_proc(& ab, RegUse_(resolve_look_at__input_and_sub_proc) { @@ -216,16 +217,16 @@ internal void resolve_look_at_init(void) { }); /* === ATOM 4: cross uz×ux→up === */ - U4 r_a_4 = R_T0; - U4 r_b_4 = R_T1; - U4 r_c_4 = R_T2; - U4 r_d_4 = R_T3; - U4 r_f_4 = R_T5; /* out ptr (HARDCODED: scratch+64) */ - U4 r_g_4 = R_T6; /* a ptr = scratch+16 */ - U4 r_h_4 = R_T7; /* b ptr = scratch+48 */ + regfile_reset_to_mask(& rf, pin_mask); smem.resolve_look_at_atom_addrs[4] = resolve_look_at__cross_uz_ux_to_up_proc(& ab, - R_ResolveScratch, - r_a_4, r_b_4, r_c_4, r_d_4, r_f_4, r_g_4, r_h_4); + RegUse_(resolve_look_at__cross_uz_ux_to_up_proc){ + .scratch = R_ResolveScratch, + .a = ralloc_v3(), /* T0 T1 T2 */ + .b = ralloc_v3(), /* T3 T5 T6 */ + .t0 = ralloc(), /* T7 = up */ + .t1 = ralloc(), /* V0 = uz / rt11 */ + .t2 = ralloc(), /* V1 = ux / rt22 */ + }); /* === ATOM 5: normalize up→uy === */ src_offset = O_(ResolveLookAtScratch, up);