more reviewing, thinking about atom bundles...

This commit is contained in:
ed
2026-08-16 01:22:53 -04:00
parent 1a0d417649
commit 3faccfc283
7 changed files with 242 additions and 238 deletions
+19 -4
View File
@@ -130,12 +130,27 @@ WORD_COUNT(mac_store_p3s4, 3)
WORD_COUNT(mac_add_si_v3s4, 3) WORD_COUNT(mac_add_si_v3s4, 3)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_sub_v3s4(rds_x, rds_y, rds_z, rt_x, rt_y, rt_z) \ #define mac_sub_s_v3(dx, dy, dz, sx, sy, sz, tx, ty, tz) \
sub_s(rds_x, rds_x, rt_x) \ sub_s(dx, sx, tx) \
, sub_s(rds_y, rds_y, rt_y) \ , sub_s(dy, sy, ty) \
, sub_s(rds_z, rds_z, rt_z) , sub_s(dz, sz, tz)
WORD_COUNT(mac_sub_s_v3, 3)
#define mac_sub_v3s4(d, s, t) \
mac_sub_s_v3(d.x, d.y, d.z, s.x, s.y, s.z, t.x, t.y, t.z)
WORD_COUNT(mac_sub_v3s4, 3) WORD_COUNT(mac_sub_v3s4, 3)
/* atom_dbg_skip */
#define mac_sub_s_v3_self(ds_x, ds_y, ds_z, tx, ty, tz) \
sub_s(ds_x, ds_x, tx) \
, sub_s(ds_y, ds_y, ty) \
, sub_s(ds_z, ds_z, tz)
WORD_COUNT(mac_sub_s_v3_self, 3)
#define mac_sub_v3s4_self(ds, t) \
mac_sub_s_v3_self(ds.x, ds.y, ds.z, t.x, t.y, t.z)
WORD_COUNT(mac_sub_v3s4_self, 3)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_store_rects2(rt_x, rt_y, rt_width, rt_height, base, offset) \ #define mac_store_rects2(rt_x, rt_y, rt_width, rt_height, base, offset) \
store_half(rt_x, base, offset + O_(Rect_S2,x)) \ store_half(rt_x, base, offset + O_(Rect_S2,x)) \
+1 -1
View File
@@ -33,7 +33,7 @@ enum {
atom_offset_example_atom_proc_skip = _atom_offset_example_atom_proc_skip, atom_offset_example_atom_proc_skip = _atom_offset_example_atom_proc_skip,
}; };
// --- atom: normalize_v3s4_proc (61 words) --- // --- atom: build_normalize_v3s4 (61 words) ---
#define _atom_offset_aligned_done_srav_path 3 #define _atom_offset_aligned_done_srav_path 3
#define _atom_offset_srav_path_aligned_done 4 #define _atom_offset_srav_path_aligned_done 4
+11 -3
View File
@@ -236,8 +236,13 @@ internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804, 0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804,
}; };
typedef Struct_(RegUse_normalize_v3s4_proc) { typedef Struct_(Binds_build_normalize_v3s4) {
Reg const scratch; // Scratch base carrier. U4 scratch;
U2 src_offset;
U2 dst_offset;
};
typedef Struct_(RegUse_build_normalize_v3s4) {
Reg scratch;
Reg src_ptr; Reg src_ptr;
Reg dst_ptr; Reg dst_ptr;
Reg recip_est; // |v|² sum + shift-input + sqrtbl[index] Reg recip_est; // |v|² sum + shift-input + sqrtbl[index]
@@ -278,8 +283,11 @@ typedef Struct_(RegUse_normalize_v3s4_proc) {
* Sqrtbl: hardcoded to 0x800185B4 (libgte msc02.rel.data). Note: swapped to local. * Sqrtbl: hardcoded to 0x800185B4 (libgte msc02.rel.data). Note: swapped to local.
* Pipeline: clobbers IR0..3, MAC1..3, LZCS, LZCR. * Pipeline: clobbers IR0..3, MAC1..3, LZCS, LZCR.
*/ */
internal MipsAtom* normalize_v3s4_proc(AtomArena_R aa, U2 src_offset, U2 dst_offset, RegUse_normalize_v3s4_proc r) internal MipsAtom* build_normalize_v3s4(AtomArena_R aa, U2 src_offset, U2 dst_offset, RegUse_build_normalize_v3s4 r)
MipsAtom_Proc_(aa, { MipsAtom_Proc_(aa, {
// load_word(r.scratch, R_TapePtr, O_(Binds_build_normalize_v3s4,scratch)),
// add_ui_self(R_TapePtr, S_(Binds_build_normalize_v3s4)),
add_si(r.src_ptr, r.scratch, src_offset), /* r_src_ptr = &src */ add_si(r.src_ptr, r.scratch, src_offset), /* r_src_ptr = &src */
/* Load src.x/y/z from r_src_ptr (caller-determined address) into r_tmp/r_recip_est/r_branch_tmp. /* Load src.x/y/z from r_src_ptr (caller-determined address) into r_tmp/r_recip_est/r_branch_tmp.
+18 -4
View File
@@ -66,12 +66,26 @@ atom_dbg_skip MipsAtomComp_Proc_(ab, {
add_si(rt_z, base, O_(V3_S4,z)), add_si(rt_z, base, O_(V3_S4,z)),
}) })
FI_ Slice_MipsCode ac_sub_v3s4(AtomBuilder_R ab, U4 rds_x, U4 rds_y, U4 rds_z, U4 rt_x, U4 rt_y, U4 rt_z) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_sub_s_v3(AtomBuilder_R ab
sub_s(rds_x, rds_x, rt_x), , Reg dx, Reg dy, Reg dz
sub_s(rds_y, rds_y, rt_y), , Reg sx, Reg sy, Reg sz
sub_s(rds_z, rds_z, rt_z), , Reg tx, Reg ty, Reg tz
) atom_dbg_skip MipsAtomComp_Proc_(ab, {
sub_s(dx, sx, tx),
sub_s(dy, sy, ty),
sub_s(dz, sz, tz),
}) })
FI_ Slice_MipsCode ac_sub_v3s4(AtomBuilder_R ab, Reg_(V3_S4) d, Reg_(V3_S4) s, Reg_(V3_S4) t) MipsAtomComp_ProcMap_(ab, mac_sub_s_v3(d.x, d.y, d.z, s.x, s.y, s.z, t.x, t.y, t.z))
FI_ Slice_MipsCode ac_sub_s_v3_self(AtomBuilder_R ab, Reg ds_x, Reg ds_y, Reg ds_z, Reg tx, Reg ty, Reg tz) atom_dbg_skip MipsAtomComp_Proc_(ab, {
sub_s(ds_x, ds_x, tx),
sub_s(ds_y, ds_y, ty),
sub_s(ds_z, ds_z, tz),
})
FI_ Slice_MipsCode ac_sub_v3s4_self(AtomBuilder_R ab, Reg_(V3_S4) ds, Reg_(V3_S4) t) MipsAtomComp_ProcMap_(ab, mac_sub_s_v3_self(ds.x, ds.y, ds.z, t.x, t.y, t.z))
FI_ Slice_MipsCode ac_store_rects2(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 rt_width, U4 rt_height, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_store_rects2(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 rt_width, U4 rt_height, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, {
store_half(rt_x, base, offset + O_(Rect_S2,x)), store_half(rt_x, base, offset + O_(Rect_S2,x)),
store_half(rt_y, base, offset + O_(Rect_S2,y)), store_half(rt_y, base, offset + O_(Rect_S2,y)),
+2 -2
View File
@@ -8,7 +8,7 @@
#pragma region hello_camera #pragma region hello_camera
// --- atom: pad_input_cube_rotation (60 words) --- // --- atom: pad_input_cube_rotation (61 words) ---
#define _atom_offset_dpad_left_exit_dpad_left 6 #define _atom_offset_dpad_left_exit_dpad_left 6
#define _atom_offset_dpad_right_exit_dpad_right 6 #define _atom_offset_dpad_right_exit_dpad_right 6
@@ -44,7 +44,7 @@ enum {
atom_offset_circle_z_exit_circle_z = _atom_offset_circle_z_exit_circle_z, atom_offset_circle_z_exit_circle_z = _atom_offset_circle_z_exit_circle_z,
}; };
// --- atom: cube_g4_face (76 words) --- // --- atom: cube_g4_face (75 words) ---
#define _atom_offset_cull_cube_g4_face_exit 41 #define _atom_offset_cull_cube_g4_face_exit 41
#define _atom_offset_bounds_chk_cube_g4_face_exit 24 #define _atom_offset_bounds_chk_cube_g4_face_exit 24
+104 -140
View File
@@ -94,6 +94,26 @@ MipsAtomComp_Proc_(ab, {
#pragma region Atom Procs #pragma region Atom Procs
// Modular Atoms // Modular Atoms
#define AtomBundle_(name) Struct_(tmpl(AtomBundle,name))
#define AtomBundle_Len(name) S_(tmpl(AtomBundle,name))/S_(MipsAtom*)
#define AtomBundleEntry_(bundle,entry) tmpl(bundle,entry)
#pragma region resolve_look_at
/* ─── resolve_look_at bundle chain atoms ──────────────────────────── */
typedef AtomBundle_(resolve_look_at) { MipsAtom*
input_and_sub,
normalize_fwd_uz,
cross_uz_up_into_right,
normalize_right_ux,
cross_uz_ux_to_up,
normalize_up_uy,
populate,
set_gte_mt3s2s4,
matrix_vector,
trans_matrix;
};
enum { enum {
// TODO(Ed): We can resolve scratch at anytime its fixed to a specific address. // TODO(Ed): We can resolve scratch at anytime its fixed to a specific address.
R_ResolveScratch = R_T4 atom_reg atom_type(U4*), R_ResolveScratch = R_T4 atom_reg atom_type(U4*),
@@ -119,16 +139,13 @@ typedef Struct_(ResolveLookAtScratch) {
V3_S4 up_in; /* offset +128 (16 bytes) */ V3_S4 up_in; /* offset +128 (16 bytes) */
}; };
/* ─── resolve_look_at bundle chain atoms ──────────────────────────── */
typedef Struct_(Binds_ResolveLookAtSub) { typedef Struct_(Binds_ResolveLookAtSub) {
P3_S4* target; /* U4 (C-side P3_S4* — read by atom 0 directly; NOT a scratchpad address) */ P3_S4* target; /* U4 (C-side P3_S4* — read by atom 0 directly; NOT a scratchpad address) */
P3_S4* eye; /* U4 (C-side P3_S4* — read by atom 0 directly; staged into scratchpad by atom 0) */ P3_S4* eye; /* U4 (C-side P3_S4* — read by atom 0 directly; staged into scratchpad by atom 0) */
V3_S4* up_in; /* U4 (C-side V3_S4* — read by atom 0 directly; staged into scratchpad by atom 0) */ V3_S4* up_in; /* U4 (C-side V3_S4* — read by atom 0 directly; staged into scratchpad by atom 0) */
ResolveLookAtScratch* scratchpad; ResolveLookAtScratch* scratchpad;
}; };
typedef Struct_(RegUse_resolve_look_at_input_and_sub) {
typedef Struct_(RegUse_resolve_look_at__input_and_sub_proc) {
Reg scratch; Reg scratch;
Reg target; Reg eye; Reg up_in; Reg target; Reg eye; Reg up_in;
Reg t0; Reg t1; Reg t2; Reg t3; Reg t4; Reg t0; Reg t1; Reg t2; Reg t3; Reg t4;
@@ -151,26 +168,27 @@ typedef Struct_(RegUse_resolve_look_at__input_and_sub_proc) {
* R_V0 : hardcoded (load eye.z / target.z) * R_V0 : hardcoded (load eye.z / target.z)
* Pool cost: 8 GPRs + R_T4 (carrier) + R_AT + R_V0 (hardcoded) = 11 GPRs. * Pool cost: 8 GPRs + R_T4 (carrier) + R_AT + R_V0 (hardcoded) = 11 GPRs.
*/ */
internal MipsAtom* resolve_look_at__input_and_sub_proc(AtomArena_R aa, RegUse_resolve_look_at__input_and_sub_proc r) // internal MipsAtom* resolve_look_at_input_and_sub(AtomArena_R aa, RegUse_resolve_look_at_input_and_sub r)
internal MipsAtom* AtomBundleEntry_(resolve_look_at,input_and_sub)(AtomArena_R aa, RegUse_resolve_look_at_input_and_sub r)
atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, { atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)), load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)),
load_word(r.eye, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)), load_word(r.eye, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)),
load_word(r.up_in, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)), load_word(r.up_in, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)),
load_word(r.scratch, R_TapePtr, O_(Binds_ResolveLookAtSub,scratchpad)), load_word(r.scratch, R_TapePtr, O_(Binds_ResolveLookAtSub,scratchpad)),
add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtSub)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtSub)),
/* Stage up_in.x/y/z into the scratchpad. */ /* Stage up_in.x/y/z into the scratchpad. */
mac_load_word_v3( r.t0, r.t1, r.t2, r.up_in, 0), mac_load_word_v3( r.t0, r.t1, r.t2, r.up_in, 0), LdSlot_
mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,up_in)), mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,up_in)),
// Stage eye.x/y/z into the scratchpad (atom 6 reads these for the translation column). // Stage eye.x/y/z into the scratchpad (atom 6 reads these for the translation column).
mac_load_word_v3( r.t0, r.t1, r.t2, r.eye, 0), mac_load_word_v3( r.t0, r.t1, r.t2, r.eye, 0), LdSlot_
mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,eye)), mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,eye)),
/* Compute fwd = target - eye. */ /* Compute fwd = target - eye. */
// mac_load_p3s4(t3, R_AT, t4, r.eye, 0), // mac_load_p3s4(t3, R_AT, t4, r.eye, 0),
mac_load_word_v3(r.t3, R_AT, r.t4, r.target, 0), mac_load_word_v3(r.t3, R_AT, r.t4, r.target, 0), LdSlot_
mac_sub_v3s4( mac_sub_s_v3_self(
r.t3, R_AT, r.t4, r.t3, R_AT, r.t4,
r.t0, r.t1, r.t2), r.t0, r.t1, r.t2),
mac_store_word_v3(r.t3, R_AT, r.t4, r.scratch, O_(ResolveLookAtScratch,fwd)), mac_store_word_v3(r.t3, R_AT, r.t4, r.scratch, O_(ResolveLookAtScratch,fwd)),
@@ -178,7 +196,7 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
mac_yield() mac_yield()
}) })
typedef Struct_(RegUse_resolve_look_at__cross_uz_up_into_right_proc) { typedef Struct_(RegUse_resolve_look_at_cross_uz_up_into_right) {
Reg scratch; Reg scratch;
Reg a; Reg b; Reg c; /* load a.x/y/z; result out.x/y/z */ Reg a; Reg b; Reg c; /* load a.x/y/z; result out.x/y/z */
Reg d; /* load b.x */ Reg d; /* load b.x */
@@ -189,8 +207,9 @@ typedef Struct_(RegUse_resolve_look_at__cross_uz_up_into_right_proc) {
Reg t0; Reg t0;
}; };
/* Atom 2: cross uz × up_in → right. */ /* Atom 2: cross uz × up_in → right. */
internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa, // internal MipsAtom* AtomBundleEntry_(resolve_look_at, cross_uz_up_to_right)(AtomArena_R aa,
RegUse_resolve_look_at__cross_uz_up_into_right_proc r internal MipsAtom* resolve_look_at_cross_uz_up_into_right(AtomArena_R aa,
RegUse_resolve_look_at_cross_uz_up_into_right r
) MipsAtom_Proc_(aa, { ) MipsAtom_Proc_(aa, {
/* FIX: build packed RT22+RT33 with proper sign extension. */ /* FIX: build packed RT22+RT33 with proper sign extension. */
add_si(r.g, r.scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */ add_si(r.g, r.scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */
@@ -199,7 +218,7 @@ internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa,
nop, nop,
/* Load a (uz).x/y/z into r_a/r_b/r_c. */ /* Load a (uz).x/y/z into r_a/r_b/r_c. */
mac_load_word_v3(r.a, r.b, r.c, r.g, 0), mac_load_word_v3(r.a, r.b, r.c, r.g, 0), LdSlot_
/* Load b (up_in).x/y/z into r_d + R_AT/R_V0 (R_AT/R_V0 are hardcoded scratch). */ /* Load b (up_in).x/y/z into r_d + R_AT/R_V0 (R_AT/R_V0 are hardcoded scratch). */
mac_load_word_v3(r.d, R_AT, r.t0, r.h, 0), LdSlot_ // (taken by gte_mv_from_ctrl_r) mac_load_word_v3(r.d, R_AT, r.t0, r.h, 0), LdSlot_ // (taken by gte_mv_from_ctrl_r)
@@ -214,7 +233,7 @@ internal MipsAtom* resolve_look_at__cross_uz_up_into_right_proc(AtomArena_R aa,
* The $2 and $4 writes don't clobber each other (separate registers). * The $2 and $4 writes don't clobber each other (separate registers).
* The 2nd ctc2 DOES clobber $4.low (becomes a.z.low, NOT a.y.high), but since OP * The 2nd ctc2 DOES clobber $4.low (becomes a.z.low, NOT a.y.high), but since OP
* reads RT22 from $2.high (which the 2nd ctc2 doesn't touch), D2 is still a.y.high. * reads RT22 from $2.high (which the 2nd ctc2 doesn't touch), D2 is still a.y.high.
* This is libpsyx's OuterProduct12 convention EXACTLY. */ * This is libpsyx's OuterProduct12 convention. */
gte_mv_to_ctrl_r(r.b, gte_cr_RT13), /* $2 = r_b = a.y. RT13=a.y.low, RT22=a.y.high. */ gte_mv_to_ctrl_r(r.b, gte_cr_RT13), /* $2 = r_b = a.y. RT13=a.y.low, RT22=a.y.high. */
gte_mv_to_ctrl_r(r.c, gte_cr_RT22), /* $4 = r_c = a.z. RT22=a.z.low, RT33=a.z.high. */ gte_mv_to_ctrl_r(r.c, gte_cr_RT22), /* $4 = r_c = a.z. RT22=a.z.low, RT33=a.z.high. */
@@ -269,11 +288,8 @@ internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa,
add_si(r.uz, r.scratch, O_(ResolveLookAtScratch,uz)), /* r.uz = &uz */ 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.ux, r.scratch, O_(ResolveLookAtScratch,ux)), /* r.ux = &ux */
add_si(r.up, r.scratch, O_(ResolveLookAtScratch,up)), /* r.up = &up (out) */ add_si(r.up, r.scratch, O_(ResolveLookAtScratch,up)), /* r.up = &up (out) */
nop,
/* Load a (uz).x/y/z into r.a. */ mac_load_v3s4(r.a, r.uz, 0), LdSlot_
mac_load_v3s4(r.a, r.uz, 0), LdSlot_ 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 */ 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. /* OP reads D1/D2/D3 from RT11/RT22/RT33 ($0/$2/$4), not V0/V1/V2.
@@ -287,8 +303,7 @@ internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa,
* OP reads D1 = RT11 from $0.low, D2 = RT22 from $2.high, D3 = RT33 from $4.high. * 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 * 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). * 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. * 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.a.y, gte_cr_RT13), /* $2 = uz.y. RT13=uz.y.low, RT22=uz.y.high. */ 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.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. */ gte_mv_to_ctrl_r(r.a.x, gte_cr_RT11), /* $0 = uz.x. RT11=uz.x. */
@@ -300,7 +315,7 @@ internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa,
gte_mv_to_data_r(r.b.z, C2_IR3), /* IR3 = ux.z */ gte_mv_to_data_r(r.b.z, C2_IR3), /* IR3 = ux.z */
GteDelay_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ GteDelay_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */
gte_cmdw_outer_product, gte_cmdw_cross,
/* Restore the RT slots we clobbered. */ /* Restore the RT slots we clobbered. */
gte_mv_to_ctrl_r(r.rt11, gte_cr_RT11), /* restore C2 $0 (RT11|RT12) */ gte_mv_to_ctrl_r(r.rt11, gte_cr_RT11), /* restore C2 $0 (RT11|RT12) */
@@ -332,20 +347,16 @@ typedef Struct_(RegUse_resolve_look_at__populate_proc) {
* MT3_S2S4 { A3x3_S2 m; A3_S4 t; } * MT3_S2S4 { A3x3_S2 m; A3_S4 t; }
* m[][] is S2 packed (9 × 2 = 18 bytes at offset 0) * m[][] is S2 packed (9 × 2 = 18 bytes at offset 0)
* t[0/1/2] is S4 (3 × 4 = 12 bytes at offset 18) * t[0/1/2] is S4 (3 × 4 = 12 bytes at offset 18)
*
* ux/uy/uz stay dedicated address regs for the whole body.
* row is the S4 load / S2 store transfer, reused per matrix row.
* Eye is not read here — atom 6b reads it.
*/ */
internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa, internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa,
RegUse_resolve_look_at__populate_proc r RegUse_resolve_look_at__populate_proc r
) MipsAtom_Proc_(aa, { ) MipsAtom_Proc_(aa, {
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)), load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)),
add_si(r.ux, r.scratch, O_(ResolveLookAtScratch,ux)), /* r.ux = &ux */ 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 */ 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 */ 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.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.uy, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4,m[1])),
@@ -356,26 +367,15 @@ internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa,
mac_yield() mac_yield()
}) })
/* Atom 6b in the bundle: matrix-vector product off = R * (-eye) >> 12. typedef Struct_(RegUse_resolve_look_at__matrix_vector_proc) {
* Uses RTPS with V0 loaded from scratch via lwc2. The RT matrix is Reg const scratch;
* pre-loaded by atom 6a.5 (resolve_look_at__load_rt). Reg look_at;
* Stores off to scratch+96 (overwriting the packed pos). 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.
* *
* GPR codes (assigned by resolve_look_at_init): * C11 ApplyMatrixLV:
* r_scratch : R_ResolveScratch (R_T4) — scratch base
* r_peye : pointer to eye (slot +96, reused as off destination)
* r_tmp0/1/2: -eye + GTE transfer scratch
*
* Pool cost: r_scratch (carrier) + 1 ptr reg + 3 tmp regs = 5 GPRs.
*/
internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa
, U4 r_scratch
, U4 r_peye
, U4 r_look_at
, U4 r_tmp0, U4 r_tmp1, U4 r_tmp2
) MipsAtom_Proc_(aa, {
/* === EXACT C11 ApplyMatrixLV replication ===
* The C11 does:
* 1. ctc2 RT matrix (5 ctc2s to C2[0..4]) * 1. ctc2 RT matrix (5 ctc2s to C2[0..4])
* 2. lw v.x/y/z from memory * 2. lw v.x/y/z from memory
* 3. S15 decomposition (negu + sra 15 + negu + andi 0x7FFF + negu) * 3. S15 decomposition (negu + sra 15 + negu + andi 0x7FFF + negu)
@@ -384,64 +384,32 @@ internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa
* 6. mtc2 LOW bits to IR1/2/3, nop, MVMVA pass2 (sf=1, mx=0, v=3, cv=3) * 6. mtc2 LOW bits to IR1/2/3, nop, MVMVA pass2 (sf=1, mx=0, v=3, cv=3)
* 7. mfc2 MACs * 7. mfc2 MACs
* 8. Combine: (pass1 << 3) + pass2 * 8. Combine: (pass1 << 3) + pass2
* */
* For S16-fitting pos (|pos| < 32768), pos >> 15 = 0, so pass1 = 0. internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa,
* The combine simplifies: result = 0 + pass2 = pass2. RegUse_resolve_look_at__matrix_vector_proc r
* So we skip the S15 decomposition and just do pass 2 directly. ) MipsAtom_Proc_(aa, {
* We still use v=3 (IR input) and mx=0 (RT matrix) like the C11. */ load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)),
/* Pop look_at* from tape. */ /* Load RT from look_at.m into C2[0..4]. Packed S2 pairs, same as set_gte_mt3s2s4. */
load_word(r_look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)), 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 */
add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)), 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 */
/* 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),
GteDelay_ nop2,
/* r_peye = &eye (slot +96, reused as off destination). */ /* MVMVA pass 2 — C11 ApplyMatrixLV command.
add_si(r_peye, r_scratch, O_(ResolveLookAtScratch,eye)),
nop,
/* === Load RT matrix from look_at into C2[0..4] via ctc2 ===
* Exact s ame sequence as set_gte_mt3s2s4 / C11's ApplyMatrixLV. */
load_word( r_tmp0, r_look_at, 0), nop, gte_mv_to_ctrl_r(r_tmp0, gte_cr_RT11),
load_word( r_tmp0, r_look_at, 4), nop, gte_mv_to_ctrl_r(r_tmp0, gte_cr_RT12),
load_word( r_tmp0, r_look_at, 8), nop, gte_mv_to_ctrl_r(r_tmp0, gte_cr_RT13),
load_word( r_tmp0, r_look_at, 12), nop, gte_mv_to_ctrl_r(r_tmp0, gte_cr_RT21),
load_half_u(r_tmp0, r_look_at, 16), nop, gte_mv_to_ctrl_r(r_tmp0, gte_cr_RT22),
nop2, /* CTC2 retirement (2 slots × 5 ctc2s) */
/* Load pos = -eye after the matrix load releases r_tmp0. */
load_word(r_tmp0, r_peye, O_(P3_S4,x)),
load_word(r_tmp1, r_peye, O_(P3_S4,y)),
load_word(r_tmp2, r_peye, O_(P3_S4,z)),
nop,
sub_u(r_tmp0, R_0, r_tmp0), /* pos.x = -eye.x */
sub_u(r_tmp1, R_0, r_tmp1),
sub_u(r_tmp2, R_0, r_tmp2),
/* === 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. */
/* Mask pos to 16 bits to be safe. For S16-fitting pos, pos & 0xFFFF
* gives the correct S16 value (sign bit preserved). */
/* r_tmp0/1/2 already have pos values. */
gte_mv_to_data_r(r_tmp0, C2_IR1),
gte_mv_to_data_r(r_tmp1, C2_IR2),
gte_mv_to_data_r(r_tmp2, C2_IR3),
nop2, /* MTC2 retirement (2 slots) */
/* === MVMVA pass 2 — C11 ApplyMatrixLV command ===
* sf=1, mx=0 (RT), v=3 (IR), cv=3. Reads RT × IR >> 12. */ * sf=1, mx=0 (RT), v=3 (IR), cv=3. Reads RT × IR >> 12. */
gte_cmdw_mvmva_c11_pass2, gte_cmdw_mvmva_c11_pass2, GteDelay_ nop,
nop, /* GTE interlock */ 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),
/* === mfc2 MAC1/2/3 → r_tmp0/1/2 === */
gte_mv_from_data_r(r_tmp0, C2_MAC1),
gte_mv_from_data_r(r_tmp1, C2_MAC2),
gte_mv_from_data_r(r_tmp2, C2_MAC3),
nop,
/* === Store off → scratch+96 (overwriting pos) === */
store_word(r_tmp0, r_peye, O_(V3_S4,x)),
store_word(r_tmp1, r_peye, O_(V3_S4,y)),
store_word(r_tmp2, r_peye, O_(V3_S4,z)),
mac_yield() mac_yield()
}) })
@@ -461,19 +429,15 @@ I_ MipsAtom* resolve_look_at__trans_matrix_proc(AtomArena_R aa
, U4 r_look_at, U4 r_scratch, U4 r_off_ptr , U4 r_look_at, U4 r_scratch, U4 r_off_ptr
, U4 r_tmp0, U4 r_tmp1, U4 r_tmp2 , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2
) MipsAtom_Proc_(aa, { ) MipsAtom_Proc_(aa, {
/* Pop look_at* from tape. */
// load_word(r_Vlook_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
// add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)),
/* r_off_ptr = &off (= &scratch.eye since atom 6b overwrote eye with off). */ /* r_off_ptr = &off (= &scratch.eye since atom 6b overwrote eye with off). */
add_si(r_off_ptr, r_scratch, O_(ResolveLookAtScratch,eye)), add_si(r_off_ptr, r_scratch, O_(ResolveLookAtScratch,eye)), nop,
nop,
/* Copy off → look_at.t[] (mac_trans_matrix: m->t = v). */ /* 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), mac_trans_mt3s3s4(r_look_at, r_off_ptr, r_tmp0, r_tmp1, r_tmp2),
mac_yield() mac_yield()
}) })
#pragma endregion resolve_look_at
#pragma endregion Atom Procs #pragma endregion Atom Procs
@@ -605,15 +569,15 @@ internal MipsAtom_(pad_input_cube_rotation) atom_info(atom_bind(Binds_PadApplyIn
load_word(R_PadStateT5, R_TapePtr, O_(Binds_PadApplyInput,state)), load_word(R_PadStateT5, R_TapePtr, O_(Binds_PadApplyInput,state)),
load_word(R_CubeRot, R_TapePtr, O_(Binds_PadApplyInput,cube_rot)), load_word(R_CubeRot, R_TapePtr, O_(Binds_PadApplyInput,cube_rot)),
load_word(R_FloorRot, R_TapePtr, O_(Binds_PadApplyInput,floor_rot)), load_word(R_FloorRot, R_TapePtr, O_(Binds_PadApplyInput,floor_rot)),
add_ui_self( R_TapePtr, S_(Binds_PadApplyInput)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_PadApplyInput)),
/* Load pad[0].buttons into R_T0. */ /* Load pad[0].buttons into R_T0. */
load_word(R_T0, R_PadStateT5, O_(PadState,buttons)), nop, load_word(R_T0, R_PadStateT5, O_(PadState,buttons)), LdSlot_ nop,
// Note(Ed): Potential op with delay slot? // Note(Ed): Potential op with delay slot?
/* D-pad Left: cube_rot.y += 30, floor_rot.y += 5. */ /* D-pad Left: cube_rot.y += 30, floor_rot.y += 5. */
and_i(R_T3, R_T0, Pad_Left), branch_le_zero(R_T3, atom_offset(dpad_left, exit_dpad_left)), and_i(R_T3, R_T0, Pad_Left), branch_le_zero(R_T3, atom_offset(dpad_left, exit_dpad_left)), BdSlot_
load_half( R_T4, R_CubeRot, O_(V3_S2,y)), /* BD-slot */ load_half( R_T4, R_CubeRot, O_(V3_S2,y)), LdSlot_
load_half( R_T3, R_FloorRot, O_(V3_S2,y)), load_half( R_T3, R_FloorRot, O_(V3_S2,y)),
add_si( R_T4, R_T4, 30), add_si( R_T4, R_T4, 30),
add_si( R_T3, R_T3, 5), add_si( R_T3, R_T3, 5),
@@ -622,8 +586,8 @@ internal MipsAtom_(pad_input_cube_rotation) atom_info(atom_bind(Binds_PadApplyIn
atom_label(exit_dpad_left) atom_label(exit_dpad_left)
/* D-pad Right: cube_rot.y -= 30, floor_rot.y -= 5. */ /* D-pad Right: cube_rot.y -= 30, floor_rot.y -= 5. */
and_i(R_T3, R_T0, Pad_Right), branch_le_zero(R_T3, atom_offset(dpad_right, exit_dpad_right)), and_i(R_T3, R_T0, Pad_Right), branch_le_zero(R_T3, atom_offset(dpad_right, exit_dpad_right)), BdSlot_
load_half( R_T4, R_CubeRot, O_(V3_S2,y)), /* BD-slot */ load_half( R_T4, R_CubeRot, O_(V3_S2,y)), LdSlot_
load_half( R_T3, R_FloorRot, O_(V3_S2,y)), load_half( R_T3, R_FloorRot, O_(V3_S2,y)),
add_si( R_T4, R_T4, -30), add_si( R_T4, R_T4, -30),
add_si( R_T3, R_T3, -5), add_si( R_T3, R_T3, -5),
@@ -633,7 +597,7 @@ internal MipsAtom_(pad_input_cube_rotation) atom_info(atom_bind(Binds_PadApplyIn
/* Analog left-stick X: dead zone 0x70..0x90. /* Analog left-stick X: dead zone 0x70..0x90.
* Cube delta = (0x80 - left_x) >> 2; floor delta = (0x80 - left_x) >> 5. */ * Cube delta = (0x80 - left_x) >> 2; floor delta = (0x80 - left_x) >> 5. */
load_byte_u(R_T3, R_PadStateT5, O_(PadState,left.x)), load_byte_u(R_T3, R_PadStateT5, O_(PadState,left.x)), LdSlot_ //?
/* Dead-zone check: skip analog if left_x in [0x70, 0x90] inclusive. Outside dead zone on LOW side: left_x < 0x70 (strictly). /* Dead-zone check: skip analog if left_x in [0x70, 0x90] inclusive. Outside dead zone on LOW side: left_x < 0x70 (strictly).
* set_lt_u(R_T4, R_T3, R_T4=0x70) → R_T4 = (left_x < 0x70) ? 1 : 0. */ * set_lt_u(R_T4, R_T3, R_T4=0x70) → R_T4 = (left_x < 0x70) ? 1 : 0. */
@@ -642,14 +606,14 @@ internal MipsAtom_(pad_input_cube_rotation) atom_info(atom_bind(Binds_PadApplyIn
atom_label(dead_check_upper) atom_label(dead_check_upper)
/* left_x >= 0x70 → check upper bound. */ /* left_x >= 0x70 → check upper bound. */
load_byte_u(R_T3, R_PadStateT5, O_(PadState,left.x)), /* reload */ load_byte_u(R_T3, R_PadStateT5, O_(PadState,left.x)), /* reload */ LdSlot_ //?
add_ui( R_T4, R_0, PadDeadZone_HighBound), add_ui( R_T4, R_0, PadDeadZone_HighBound),
/* R_T4 = (0x90 < left_x) ? 1 : 0 → (left_x > 0x90) ? 1 : 0 */ /* R_T4 = (0x90 < left_x) ? 1 : 0 → (left_x > 0x90) ? 1 : 0 */
set_lt_u(R_T4, R_T4, R_T3), branch_ne(R_T4, R_0, atom_offset(dead_zone_high_check, dead_high_active)), set_lt_u(R_T4, R_T4, R_T3), branch_ne(R_T4, R_0, atom_offset(dead_zone_high_check, dead_high_active)), BdSlot_
add_ui( R_T4, R_0, PadDeadZone_Center), /* BD-slot: pre-load 0x80 for dead_high_active */ add_ui( R_T4, R_0, PadDeadZone_Center), /* BD-slot: pre-load 0x80 for dead_high_active */
jump_rel(atom_offset(dead_zone_skip, exit_stick)), jump_rel(atom_offset(dead_zone_skip, exit_stick)),
mac_yield_load(), BdSlot_ mac_yield_load(), LdSlot_
atom_label(dead_low_active) atom_label(dead_low_active)
/* R_T3 = left_x (from line 632 lbu; not clobbered between dead_zone_low_check branch + its BD-slot `add_ui R_T4, 0x80`). /* R_T3 = left_x (from line 632 lbu; not clobbered between dead_zone_low_check branch + its BD-slot `add_ui R_T4, 0x80`).
@@ -660,18 +624,18 @@ atom_label(dead_low_active)
/* R_T4 = cube_delta */ /* R_T4 = cube_delta */
shift_aright(R_T4, R_T3, 2), shift_aright(R_T4, R_T3, 2),
load_half( R_T0, R_CubeRot, O_(V3_S2,y)), nop, load_half( R_T0, R_CubeRot, O_(V3_S2,y)), LdSlot_ nop,
add_u( R_T0, R_T0, R_T4), add_u( R_T0, R_T0, R_T4),
store_half( R_T0, R_CubeRot, O_(V3_S2,y)), store_half( R_T0, R_CubeRot, O_(V3_S2,y)),
/* R_T4 = floor_delta — moved into the load-delay slot of the floor load below (fills the 1-instruction gap; /* R_T4 = floor_delta — moved into the load-delay slot of the floor load below (fills the 1-instruction gap;
* doesn't read R_T0; R_T4 settles by the subsequent add_u). */ * doesn't read R_T0; R_T4 settles by the subsequent add_u). */
load_half( R_T0, R_FloorRot, O_(V3_S2,y)), load_half( R_T0, R_FloorRot, O_(V3_S2,y)), LdSlot_
shift_aright(R_T4, R_T3, 5), shift_aright(R_T4, R_T3, 5),
add_u( R_T0, R_T0, R_T4), add_u( R_T0, R_T0, R_T4),
store_half( R_T0, R_FloorRot, O_(V3_S2,y)), store_half( R_T0, R_FloorRot, O_(V3_S2,y)),
jump_rel(atom_offset(end_low, exit_stick)), jump_rel(atom_offset(end_low, exit_stick)),
mac_yield_load(), BdSlot_ mac_yield_load(), LdSlot_
atom_label(dead_high_active) atom_label(dead_high_active)
/* R_T3 = left_x (from line 641 lbu in dead_check_upper; not clobbered between dead_zone_high_check branch + its BD-slot `add_ui R_T4, 0x80`). /* R_T3 = left_x (from line 641 lbu in dead_check_upper; not clobbered between dead_zone_high_check branch + its BD-slot `add_ui R_T4, 0x80`).
@@ -681,18 +645,18 @@ atom_label(dead_high_active)
/* delta = 0x80 - left_x (signed negative). */ /* delta = 0x80 - left_x (signed negative). */
shift_aright(R_T4, R_T3, 2), /* R_T4 = cube_delta (signed) */ shift_aright(R_T4, R_T3, 2), /* R_T4 = cube_delta (signed) */
load_half( R_T0, R_CubeRot, O_(V3_S2,y)), nop, load_half( R_T0, R_CubeRot, O_(V3_S2,y)), LdSlot_ nop,
add_u( R_T0, R_T0, R_T4), add_u( R_T0, R_T0, R_T4),
store_half( R_T0, R_CubeRot, O_(V3_S2,y)), store_half( R_T0, R_CubeRot, O_(V3_S2,y)),
/* R_T4 = floor_delta (signed) — moved into the load-delay slot of the floor load below. */ /* R_T4 = floor_delta (signed) — moved into the load-delay slot of the floor load below. */
load_half( R_T0, R_FloorRot, O_(V3_S2,y)), load_half( R_T0, R_FloorRot, O_(V3_S2,y)), LdSlot_
shift_aright(R_T4, R_T3, 5), shift_aright(R_T4, R_T3, 5),
add_u( R_T0, R_T0, R_T4), add_u( R_T0, R_T0, R_T4),
store_half( R_T0, R_FloorRot, O_(V3_S2,y)), store_half( R_T0, R_FloorRot, O_(V3_S2,y)),
atom_label(no_jump_fallthrough) atom_label(no_jump_fallthrough)
mac_yield_load(), mac_yield_load(), LdSlot_
atom_label(exit_stick) atom_label(exit_stick)
/* NOT mac_yield() — R_AtomJmp was already loaded in the BD-slot of the dead-zone/exit branch. */ /* NOT mac_yield() — R_AtomJmp was already loaded in the BD-slot of the dead-zone/exit branch. */
@@ -714,14 +678,14 @@ internal MipsAtom_(pad_input_cam) atom_info(atom_bind(Binds_PadInputCam)
/* Bind pop: state → R_CamPadState (R_T5), cam → R_Cam (R_T4), advance R_TapePtr by 8. */ /* Bind pop: state → R_CamPadState (R_T5), cam → R_Cam (R_T4), advance R_TapePtr by 8. */
load_word(R_CamPadState, R_TapePtr, O_(Binds_PadInputCam,state)), load_word(R_CamPadState, R_TapePtr, O_(Binds_PadInputCam,state)),
load_word(R_Cam, R_TapePtr, O_(Binds_PadInputCam,cam)), load_word(R_Cam, R_TapePtr, O_(Binds_PadInputCam,cam)),
add_ui_self( R_TapePtr, S_(Binds_PadInputCam)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_PadInputCam)),
/* Load pad[0].buttons into R_T0; nop fills the load-delay slot. */ /* Load pad[0].buttons into R_T0; nop fills the load-delay slot. */
load_word(R_T0, R_CamPadState, O_(PadState,buttons)), load_word(R_T0, R_CamPadState, O_(PadState,buttons)), LdSlot_
load_word(R_T1, R_Cam, O_(Camera,pos.x)), // BD-Slot. load_word(R_T1, R_Cam, O_(Camera,pos.x)),
// D-pad Left → cam.pos.x -= 50. and_i fulfills BD-slot for load on R_Cam. // D-pad Left → cam.pos.x -= 50. and_i fulfills BD-slot for load on R_Cam.
LdSlot_ and_i(R_T3, R_T0, Pad_Left), branch_le_zero(R_T3, atom_offset(left_x, exit_left_x)), BdSlot_ mac_yield_load(), LdSlot_ and_i(R_T3, R_T0, Pad_Left), branch_le_zero(R_T3, atom_offset(left_x, exit_left_x)), BdSlot_ mac_yield_load(), LdSlot_
add_si(R_T1, R_T1, -50), store_word(R_T1, R_Cam, O_(Camera,pos.x)), add_si(R_T1, R_T1, -50), store_word(R_T1, R_Cam, O_(Camera,pos.x)),
atom_label(exit_left_x) atom_label(exit_left_x)
@@ -780,7 +744,7 @@ internal MipsAtom_(rbind_cube_g4_face) atom_info(atom_bind(Binds_CubeTri), atom_
load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,FaceCursor)), load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,FaceCursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,VertBase)), load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,VertBase)),
load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,OtBase)), load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,OtBase)),
add_ui_self( R_TapePtr, S_(Binds_CubeTri)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_CubeTri)),
mac_yield() mac_yield()
}; };
@@ -793,20 +757,20 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
load_half_u(R_T0, R_FaceCursor, 0 * S_(S2)), load_half_u(R_T0, R_FaceCursor, 0 * S_(S2)),
load_half_u(R_T1, R_FaceCursor, 1 * S_(S2)), load_half_u(R_T1, R_FaceCursor, 1 * S_(S2)),
load_half_u(R_T2, R_FaceCursor, 2 * S_(S2)), load_half_u(R_T2, R_FaceCursor, 2 * S_(S2)),
load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)), // load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)),
mac_gte_load_tri_verts(R_VertBase, R_T0, R_T1, R_T2), LdSlot_ mac_gte_load_tri_verts(R_VertBase, R_T0, R_T1, R_T2), GteDelay_ load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)), LdSlot_
nop2, gte_cmdw_rotate_translate_perspective_triple, // required cpu -> gte delay slot GteDelay_ nop, gte_cmdw_rotate_translate_perspective_triple,
gte_cmdw_nclip, gte_cmdw_nclip,
gte_mv_from_data_r(R_T0, C2_MAC0), nop, gte_mv_from_data_r(R_T0, C2_MAC0), GteDelay_ nop,
branch_le_zero(R_T0, atom_offset(cull, cube_g4_face_exit)), branch_le_zero(R_T0, atom_offset(cull, cube_g4_face_exit)),
/* BD-slot: Write the prim tag (R_0=0; overwrites the legacy tag word in the prim_buffer). /* BD-slot: Write the prim tag (R_0=0; overwrites the legacy tag word in the prim_buffer).
* If branch IS taken (face culled), the body is skipped and this 0-tag is stranded — * If branch IS taken (face culled), the body is skipped and this 0-tag is stranded —
* harmless because the OT entry that points to this prim is created later. */ * harmless because the OT entry that points to this prim is created later. */
store_word(R_0, R_PrimCursor, O_(Poly_G4, tag)), BdSlot_ store_word(R_0, R_PrimCursor, O_(Poly_G4, tag)),
shift_lleft(R_AT, R_T3, v3s2_byteoff), add_u(R_AT, R_AT, R_VertBase), shift_lleft(R_AT, R_T3, v3s2_byteoff), add_u(R_AT, R_AT, R_VertBase),
load_word(R_V0, R_AT, O_(V3_S2, x)), load_word(R_V1, R_AT, O_(V3_S2, z)), load_word(R_V0, R_AT, O_(V3_S2, x)), load_word(R_V1, R_AT, O_(V3_S2, z)), LdSlot_
gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0),
mac_gte_store_g4_p012(R_PrimCursor), mac_gte_store_g4_p012(R_PrimCursor),
@@ -818,7 +782,7 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
add_ui( R_AT, R_0, OrderingTbl_Len), add_ui( R_AT, R_0, OrderingTbl_Len),
set_lt_u( R_AT, R_T1, R_AT), set_lt_u( R_AT, R_T1, R_AT),
branch_equal(R_AT, R_0, atom_offset(bounds_chk, cube_g4_face_exit)), nop, branch_equal(R_AT, R_0, atom_offset(bounds_chk, cube_g4_face_exit)), BdSlot_ nop,
mac_insert_ot_tag(R_OtBase, R_PrimCursor, S_(Poly_G4)), mac_insert_ot_tag(R_OtBase, R_PrimCursor, S_(Poly_G4)),
mac_format_g4_color(R_PrimCursor, mac_format_g4_color(R_PrimCursor,
/* c0 magenta */ 0xFF, 0x00, 0xFF, /* c0 magenta */ 0xFF, 0x00, 0xFF,
@@ -850,7 +814,7 @@ MipsAtom_(rbind_floor_f3_face) atom_info(atom_bind(Binds_FloorTri), atom_phase(f
load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,FaceCursor)), load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,FaceCursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,VertBase)), load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,VertBase)),
load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,OtBase)), load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,OtBase)),
add_ui_self( R_TapePtr, S_(Binds_FloorTri)), LdSlot_ add_ui_self( R_TapePtr, S_(Binds_FloorTri)),
mac_yield() mac_yield()
}; };
@@ -897,7 +861,7 @@ internal MipsAtom_(sync_primitive_arena) atom_info(atom_bind(Binds_SyncPrimitive
, atom_writes(R_TapePtr) , atom_writes(R_TapePtr)
){ ){
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,used)), load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,used)),
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,cursor)), load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,cursor)), LdSlot_
add_ui_self( R_TapePtr, S_(Binds_SyncPrimitiveArena)), add_ui_self( R_TapePtr, S_(Binds_SyncPrimitiveArena)),
/* Calculate byte offset and store directly back to RAM */ /* Calculate byte offset and store directly back to RAM */
sub_u( R_T0, R_PrimCursor, R_T0), // R_T0 = R_PrimCursor - binds.cursor sub_u( R_T0, R_PrimCursor, R_T0), // R_T0 = R_PrimCursor - binds.cursor
+80 -77
View File
@@ -60,8 +60,12 @@ enum {
enum { enum {
Scratchpad_Len = 1024, Scratchpad_Len = 1024,
MemTape_Len = 512, MemTape_Len = 512,
ResolveLookAtArena_Words = 1024, ResolveLookAtArena_Words = 1024,
ResolveLookAtArena_Size = ResolveLookAtArena_Words * S_(MipsCode), ResolveLookAtArena_Size = ResolveLookAtArena_Words * S_(MipsCode),
CT_InitAtomMem_Words = Kilo_(4),
CT_InitAtomMem_Size = CT_InitAtomMem_Words * S_(MipsCode),
}; };
typedef Struct_(SMemory) { typedef Struct_(SMemory) {
PrimitiveArena primitives; PrimitiveArena primitives;
@@ -85,8 +89,14 @@ typedef Struct_(SMemory) {
// TODO(Ed): We don't need this we can just cast at any point an address to a desired view of scratchpad, we have the address. // TODO(Ed): We don't need this we can just cast at any point an address to a desired view of scratchpad, we have the address.
U4_V scratchpad; // d-cache U4_V scratchpad; // d-cache
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
U1 resolve_look_at_mem[ResolveLookAtArena_Size]; U1 resolve_look_at_mem[ResolveLookAtArena_Size];
MipsAtom* resolve_look_at_atom_addrs[10]; MipsAtom* resolve_look_at_bundle[AtomBundle_Len(resolve_look_at)];
}; };
global SMemory smem; global SMemory smem;
extern SMemory smem; extern SMemory smem;
@@ -131,29 +141,20 @@ I_ void resolve_look_at_c11(MT3_S2S4* look_at, P3_S4* eye, P3_S4* target, V3_S4*
} }
FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at_c11(& c->look_at, & c->pos, target, up_in); } FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at_c11(& c->look_at, & c->pos, target, up_in); }
/* Pre-build all 7 chain atoms of the resolve_look_at bundle into the static arena.
* 4 unique procs in hello_camera.atom.c (chain atoms 0, 2, 4, 6); atoms 1, 3, 5
* share the GENERIC normalize_v3s4_proc from gte.atom.c internal void compile_resolve_look_at(void) {
* 0: resolve_look_at__input_and_sub_proc
* 1: normalize_v3s4_proc (fwd → uz; offsets 0, 16)
* 2: resolve_look_at__cross_uz_up_in_to_right_proc
* 3: normalize_v3s4_proc (right → ux; offsets 32, 48)
* 4: resolve_look_at__cross_uz_ux_to_up_proc
* 5: normalize_v3s4_proc (up → uy; offsets 64, 80)
* 6: resolve_look_at__populate_and_translate_proc
*/
internal void resolve_look_at_init(void) {
/* Wrap the static arena in a MipsAtomBuilder. */ /* Wrap the static arena in a MipsAtomBuilder. */
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem)); AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
TapeBuilder tb = tb_make(slice_ut_arr(smem.resolve_look_at_atom_addrs)); TapeBuilder tb = tb_make(slice_ut_arr(smem.resolve_look_at_bundle));
U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch); U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch);
RegFile rf = regfile(pin_mask); RegFile rf = regfile(pin_mask);
#define ralloc() regfile_alloc(& rf) #define ralloc() regfile_alloc(& rf)
#define ralloc_v3() { ralloc(), ralloc(), ralloc() } #define ralloc_v3() { ralloc(), ralloc(), ralloc() }
smem.resolve_look_at_atom_addrs[0] = resolve_look_at__input_and_sub_proc(& ab, tb_emit_(AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab,
RegUse_(resolve_look_at__input_and_sub_proc) { RegUse_(resolve_look_at_input_and_sub) {
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.target = ralloc(), .target = ralloc(),
.eye = ralloc(), .eye = ralloc(),
@@ -164,14 +165,14 @@ internal void resolve_look_at_init(void) {
.t3 = ralloc(), .t3 = ralloc(),
.t4 = ralloc(), .t4 = ralloc(),
} }
); ));
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 1: normalize fwd→uz === */ /* === ATOM 1: normalize fwd→uz === */
U2 src_offset = O_(ResolveLookAtScratch, fwd); U2 src_offset = O_(ResolveLookAtScratch, fwd);
U2 dst_offset = O_(ResolveLookAtScratch, uz); U2 dst_offset = O_(ResolveLookAtScratch, uz);
smem.resolve_look_at_atom_addrs[1] = normalize_v3s4_proc(& ab, smem.resolve_look_at_bundle[1] = build_normalize_v3s4(& ab,
src_offset, dst_offset, RegUse_(normalize_v3s4_proc){ src_offset, dst_offset, RegUse_(build_normalize_v3s4){
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.src_ptr = ralloc(), .src_ptr = ralloc(),
.dst_ptr = ralloc(), .dst_ptr = ralloc(),
@@ -186,8 +187,9 @@ internal void resolve_look_at_init(void) {
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 2: cross uz×up_in→right === */ /* === ATOM 2: cross uz×up_in→right === */
smem.resolve_look_at_atom_addrs[2] = resolve_look_at__cross_uz_up_into_right_proc(& ab, // smem.resolve_look_at_bundle[2] = AtomBundleEntry_(resolve_look_at,cross_uz_up_to_right)(& ab,
RegUse_(resolve_look_at__cross_uz_up_into_right_proc) { smem.resolve_look_at_bundle[2] = resolve_look_at_cross_uz_up_into_right(& ab,
RegUse_(resolve_look_at_cross_uz_up_into_right) {
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.a = ralloc(), .a = ralloc(),
.b = ralloc(), .b = ralloc(),
@@ -198,27 +200,28 @@ internal void resolve_look_at_init(void) {
.t2 = ralloc(), .t2 = ralloc(),
.t0 = ralloc(), .t0 = ralloc(),
}); });
regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 3: normalize right→ux === */ /* === ATOM 3: normalize right→ux === */
src_offset = O_(ResolveLookAtScratch, right); src_offset = O_(ResolveLookAtScratch, right);
dst_offset = O_(ResolveLookAtScratch, ux); dst_offset = O_(ResolveLookAtScratch, ux);
smem.resolve_look_at_atom_addrs[3] = normalize_v3s4_proc(& ab, smem.resolve_look_at_bundle[3] = build_normalize_v3s4(& ab,
src_offset, dst_offset, RegUse_(normalize_v3s4_proc){ src_offset, dst_offset, RegUse_(build_normalize_v3s4){
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.src_ptr = R_T0, .src_ptr = ralloc(),
.dst_ptr = R_T1, .dst_ptr = ralloc(),
.recip_est = R_T6, .recip_est = ralloc(),
.norm = R_T7, .norm = ralloc(),
.shift = R_V0, .shift = ralloc(),
.src_x = R_T2, .src_x = ralloc(),
.t3 = R_T3, .t3 = ralloc(),
.t4 = R_T5, .t4 = ralloc(),
.t5 = R_V1, .t5 = ralloc(),
}); });
regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 4: cross uz×ux→up === */ /* === ATOM 4: cross uz×ux→up === */
regfile_reset_to_mask(& rf, pin_mask); smem.resolve_look_at_bundle[4] = resolve_look_at__cross_uz_ux_to_up_proc(& ab,
smem.resolve_look_at_atom_addrs[4] = resolve_look_at__cross_uz_ux_to_up_proc(& ab,
RegUse_(resolve_look_at__cross_uz_ux_to_up_proc){ RegUse_(resolve_look_at__cross_uz_ux_to_up_proc){
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.a = ralloc_v3(), /* T0 T1 T2 */ .a = ralloc_v3(), /* T0 T1 T2 */
@@ -227,28 +230,29 @@ internal void resolve_look_at_init(void) {
.t1 = ralloc(), /* V0 = uz / rt11 */ .t1 = ralloc(), /* V0 = uz / rt11 */
.t2 = ralloc(), /* V1 = ux / rt22 */ .t2 = ralloc(), /* V1 = ux / rt22 */
}); });
regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 5: normalize up→uy === */ /* === ATOM 5: normalize up→uy === */
src_offset = O_(ResolveLookAtScratch, up); src_offset = O_(ResolveLookAtScratch, up);
dst_offset = O_(ResolveLookAtScratch, uy); dst_offset = O_(ResolveLookAtScratch, uy);
smem.resolve_look_at_atom_addrs[5] = normalize_v3s4_proc(& ab, smem.resolve_look_at_bundle[5] = build_normalize_v3s4(& ab,
src_offset, dst_offset, src_offset, dst_offset,
RegUse_(normalize_v3s4_proc){ RegUse_(build_normalize_v3s4){
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.src_ptr = R_T0, .src_ptr = ralloc(),
.dst_ptr = R_T1, .dst_ptr = ralloc(),
.recip_est = R_T6, .recip_est = ralloc(),
.norm = R_T7, .norm = ralloc(),
.shift = R_V0, .shift = ralloc(),
.src_x = R_T2, .src_x = ralloc(),
.t3 = R_T3, .t3 = ralloc(),
.t4 = R_T5, .t4 = ralloc(),
.t5 = R_V1, .t5 = ralloc(),
}); });
regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 6a: populate (m[][] from ux/uy/uz, t[]=0) === */ /* === ATOM 6a: populate (m[][] from ux/uy/uz, t[]=0) === */
regfile_reset_to_mask(& rf, pin_mask); smem.resolve_look_at_bundle[6] = resolve_look_at__populate_proc(& ab,
smem.resolve_look_at_atom_addrs[6] = resolve_look_at__populate_proc(& ab,
RegUse_(resolve_look_at__populate_proc){ RegUse_(resolve_look_at__populate_proc){
.scratch = R_ResolveScratch, .scratch = R_ResolveScratch,
.look_at = ralloc(), /* T0 */ .look_at = ralloc(), /* T0 */
@@ -257,34 +261,30 @@ internal void resolve_look_at_init(void) {
.uy = ralloc(), /* T6 = uy */ .uy = ralloc(), /* T6 = uy */
.uz = ralloc(), /* T7 = uz */ .uz = ralloc(), /* T7 = uz */
}); });
regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 6a.5: set_gte_mt3s2s4 (BAKED — ctc2 RT matrix) === /* === ATOM 6a.5: set_gte_mt3s2s4 (BAKED — ctc2 RT matrix) ===
* This is a BAKED atom from gte.atom.c. Its body hardcodes R_T3 as * This is a BAKED atom from gte.atom.c. Its body hardcodes R_T3 as
* the matrix pointer (popped from tape). It does NOT need GPR * the matrix pointer (popped from tape). It does NOT need GPR
* assignment from us — it has its own internal GPR usage. * assignment from us — it has its own internal GPR usage.
* We just take its address. */ * We just take its address. */
smem.resolve_look_at_atom_addrs[7] = (MipsAtom*) & set_gte_mt3s2s4; smem.resolve_look_at_bundle[7] = (MipsAtom*) & set_gte_mt3s2s4;
/* === ATOM 6b: matrix_vector (RT * (-eye) >> 12) === /* === ATOM 6b: matrix_vector (RT * (-eye) >> 12) === */
* Uses mac_apply_matrix_lv component macro which internally uses smem.resolve_look_at_bundle[8] = resolve_look_at__matrix_vector_proc(& ab,
* r_t0 for the RT matrix load + V0 load, then r_t0/r_t1/r_t2 RegUse_(resolve_look_at__matrix_vector_proc){
* for the mfc2/store. We pass our GPRs. */ .scratch = R_ResolveScratch,
U4 r_scratch_6b = R_ResolveScratch; .look_at = ralloc(), /* T0 */
U4 r_peye_6b = R_T1; /* scratch+96 (packed V0 dst, then off dst) */ .eye = ralloc(), /* T1 */
U4 r_look_at_6b = R_T0; /* tape pop → look_at* */ .v = ralloc_v3(), /* T2 T3 T5 */
U4 r_tmp0_6b = R_T2; });
U4 r_tmp1_6b = R_T3;
U4 r_tmp2_6b = R_T5;
smem.resolve_look_at_atom_addrs[8] = resolve_look_at__matrix_vector_proc(& ab,
r_scratch_6b, r_peye_6b, r_look_at_6b,
r_tmp0_6b, r_tmp1_6b, r_tmp2_6b);
/* === ATOM 6c: trans_matrix (off → look_at->t[]) === */ /* === ATOM 6c: trans_matrix (off → look_at->t[]) === */
U4 r_look_at_6c = R_T0; /* tape pop → look_at* */ U4 r_look_at_6c = R_T0; /* tape pop → look_at* */
U4 r_scratch_6c = R_ResolveScratch; U4 r_scratch_6c = R_ResolveScratch;
U4 r_off_ptr_6c = R_T1; /* &scratch.eye (= off dst) */ U4 r_off_ptr_6c = R_T1; /* &scratch.eye (= off dst) */
U4 r_tmp0_6c = R_T2; U4 r_tmp0_6c = R_T2;
smem.resolve_look_at_atom_addrs[9] = resolve_look_at__trans_matrix_proc(& ab, smem.resolve_look_at_bundle[9] = resolve_look_at__trans_matrix_proc(& ab,
r_look_at_6c, r_scratch_6c, r_off_ptr_6c, r_tmp0_6c, R_T3, R_T4); r_look_at_6c, r_scratch_6c, r_off_ptr_6c, r_tmp0_6c, R_T3, R_T4);
/* Sanity check: arena didn't overflow. */ /* Sanity check: arena didn't overflow. */
@@ -303,36 +303,41 @@ internal void resolve_look_at_init(void) {
* ---- * ----
* 5 tb_data words total per frame. * 5 tb_data words total per frame.
*/ */
I_ void resolve_look_at( I_ void resolve_look_at(TapeBuilder_R tb
TapeBuilder_R tb
, MT3_S2S4* look_at , MT3_S2S4* look_at
, P3_S4* eye , P3_S4* eye
, P3_S4* target , P3_S4* target
, V3_S4* up_in , V3_S4* up_in
){ ){
tb_emit(tb, smem.resolve_look_at_atom_addrs[0]); { tb_emit(tb, smem.resolve_look_at_bundle[0]); {
tb_data(tb, u4_(target)); tb_data(tb, u4_(target));
tb_data(tb, u4_(eye)); tb_data(tb, u4_(eye));
tb_data(tb, u4_(up_in)); tb_data(tb, u4_(up_in));
tb_data(tb, u4_(smem.scratchpad)); tb_data(tb, u4_(smem.scratchpad));
} }
tb_emit(tb, smem.resolve_look_at_atom_addrs[1]); { } tb_emit(tb, smem.resolve_look_at_bundle[1]); {
tb_emit(tb, smem.resolve_look_at_atom_addrs[2]); { } // tb_data(tb, u4_(Scratchpad_Loc));
tb_emit(tb, smem.resolve_look_at_atom_addrs[3]); { } }
tb_emit(tb, smem.resolve_look_at_atom_addrs[4]); { } tb_emit(tb, smem.resolve_look_at_bundle[2]); { }
tb_emit(tb, smem.resolve_look_at_atom_addrs[5]); { } tb_emit(tb, smem.resolve_look_at_bundle[3]); {
// tb_data(tb, u4_(Scratchpad_Loc));
}
tb_emit(tb, smem.resolve_look_at_bundle[4]); { }
tb_emit(tb, smem.resolve_look_at_bundle[5]); {
// tb_data(tb, u4_(Scratchpad_Loc));
}
tb_emit(tb, smem.resolve_look_at_atom_addrs[6]); { tb_emit(tb, smem.resolve_look_at_bundle[6]); {
tb_data(tb, u4_(look_at)); tb_data(tb, u4_(look_at));
} }
tb_emit(tb, smem.resolve_look_at_atom_addrs[7]); { tb_emit(tb, smem.resolve_look_at_bundle[7]); {
tb_data(tb, u4_(look_at)); tb_data(tb, u4_(look_at));
} }
tb_emit(tb, smem.resolve_look_at_atom_addrs[8]); { tb_emit(tb, smem.resolve_look_at_bundle[8]); {
tb_data(tb, u4_(look_at)); tb_data(tb, u4_(look_at));
} }
tb_emit(tb, smem.resolve_look_at_atom_addrs[9]); { tb_emit(tb, smem.resolve_look_at_bundle[9]); {
// tb_data(tb, u4_(look_at)); // tb_data(tb, u4_(look_at));
} }
} }
@@ -526,8 +531,7 @@ int main(void)
/* Direct BIOS: poll both ports during VBlank. */ /* Direct BIOS: poll both ports during VBlank. */
pad_bios_init_start(& smem.pad_raw[0], & smem.pad_raw[1]); pad_bios_init_start(& smem.pad_raw[0], & smem.pad_raw[1]);
/* Pre-build the resolve_look_at bundle atoms into the static arena. */ compile_resolve_look_at();
resolve_look_at_init();
/* Pinned registers for the GPU init atom. */ /* Pinned registers for the GPU init atom. */
register U4* io_base_addr rgcc(R_IO_BaseAddr) = u4_r(IO_BASE_ADDR); register U4* io_base_addr rgcc(R_IO_BaseAddr) = u4_r(IO_BASE_ADDR);
@@ -548,4 +552,3 @@ int main(void)
return 0; return 0;
} }
GCC_OPTIMIZATION_ENABLE GCC_OPTIMIZATION_ENABLE