finished reviewing normalize_v3s4 for now

This commit is contained in:
ed
2026-08-14 03:45:34 -04:00
parent 3a4d6304dd
commit b695056b9a
8 changed files with 226 additions and 103 deletions
+50 -5
View File
@@ -155,16 +155,21 @@ WORD_COUNT(mac_gte_store_g4_p3, 1)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_gte_sqr_v3(r_sx, r_sy, r_sz, r_sq_x, r_sq_y, r_sq_z) \ #define mac_gte_sqr_v3(r_sx, r_sy, r_sz, r_sq_x, r_sq_y, r_sq_z) \
gte_mv_to_data_r(r_sx, C2_IR1) \ mac_gte_sqr_v3s4(r_sx, r_sy, r_sz, nop) \
, gte_mv_to_data_r(r_sy, C2_IR2) \
, gte_mv_to_data_r(r_sz, C2_IR3) \
, nop \
, gte_cmdw_sqr \
, gte_mv_from_data_r(r_sq_x, C2_MAC1) \ , gte_mv_from_data_r(r_sq_x, C2_MAC1) \
, gte_mv_from_data_r(r_sq_y, C2_MAC2) \ , gte_mv_from_data_r(r_sq_y, C2_MAC2) \
, gte_mv_from_data_r(r_sq_z, C2_MAC3) , gte_mv_from_data_r(r_sq_z, C2_MAC3)
WORD_COUNT(mac_gte_sqr_v3, 8) WORD_COUNT(mac_gte_sqr_v3, 8)
/* atom_dbg_skip */
#define mac_gte_sqr_v3s4(r_sx, r_sy, r_sz, nop_slot) \
gte_mv_to_data_r(r_sx, C2_IR1) \
, gte_mv_to_data_r(r_sy, C2_IR2) \
, gte_mv_to_data_r(r_sz, C2_IR3) \
, nop_slot \
, gte_cmdw_sqr
WORD_COUNT(mac_gte_sqr_v3s4, 5)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_gte_gpf_scale(r_sx, r_sy, r_sz, r_recip_est, r_shift, r_dx, r_dy, r_dz) \ #define mac_gte_gpf_scale(r_sx, r_sy, r_sz, r_recip_est, r_shift, r_dx, r_dy, r_dz) \
gte_mv_to_data_r(r_recip_est, C2_IR0) \ gte_mv_to_data_r(r_recip_est, C2_IR0) \
@@ -190,6 +195,46 @@ WORD_COUNT(mac_gte_gpf_scale, 13)
, store_word(r_t2, r_mtx, O_(MT3_S2S4,t[2])) , store_word(r_t2, r_mtx, O_(MT3_S2S4,t[2]))
WORD_COUNT(mac_trans_mt3s3s4, 6) WORD_COUNT(mac_trans_mt3s3s4, 6)
/* atom_dbg_skip */
#define mac_lzcr_round_even_half_shift(r_shift, r_mag_sq, r_mag_sq_copy) \
and_i(r_shift, r_shift, gte_lzcr_even_mask) \
, or_u(r_mag_sq_copy, r_mag_sq, 0) \
, li_s(r_mag_sq, 31) \
, sub_s(r_mag_sq, r_mag_sq, r_shift) \
, shift_aright(r_mag_sq, r_mag_sq, 1)
WORD_COUNT(mac_lzcr_round_even_half_shift, 5)
#define mac_shift_aright_var_v3(rd_v0, rd_v1, rd_v2, rs_v0, rs_v1, rs_v2, r_shift) \
shift_aright_var(rd_v0, rs_v0, r_shift) \
, shift_aright_var(rd_v1, rs_v1, r_shift) \
, shift_aright_var(rd_v2, rs_v2, r_shift)
WORD_COUNT(mac_shift_aright_var_v3, 3)
#define mac_shift_aright_var_v3_self(rds_v0, rds_v1, rds_v2, r_shift) \
shift_aright_var(rds_v0, rds_v0, r_shift) \
, shift_aright_var(rds_v1, rds_v1, r_shift) \
, shift_aright_var(rds_v2, rds_v2, r_shift)
WORD_COUNT(mac_shift_aright_var_v3_self, 3)
#define mac_gte_general_purpose_interopolation(to_ir0, to_ir1, to_ir2, to_ir3, fr_mac1, fr_mac2, fr_mac3, nop_slot1, nop_slot2) \
gte_mv_to_data_r(to_ir0, C2_IR0) \
, 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) */ \
, LdSlot_ nop_slot1 \
, LdSlot_ nop_slot2 \
, gte_cmdw_gpf \
, gte_mv_from_data_r(fr_mac1, C2_MAC1) \
, gte_mv_from_data_r(fr_mac2, C2_MAC2) \
, gte_mv_from_data_r(fr_mac3, C2_MAC3)
WORD_COUNT(mac_gte_general_purpose_interopolation, 10)
#define mac_gte_mv_from_data_r_mac123(fr_mac1, fr_mac2, fr_mac3) \
gte_mv_from_data_r(fr_mac1, C2_MAC1) \
, gte_mv_from_data_r(fr_mac2, C2_MAC2) \
, gte_mv_from_data_r(fr_mac3, C2_MAC3)
WORD_COUNT(mac_gte_mv_from_data_r_mac123, 3)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \ #define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \
mac_load_word_imm(reg_transfer, cmd) \ mac_load_word_imm(reg_transfer, cmd) \
+1 -1
View File
@@ -25,7 +25,7 @@
#pragma region duffle #pragma region duffle
// --- atom: normalize_v3s4 (66 words) --- // --- atom: normalize_v3s4 (56 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
+136 -72
View File
@@ -11,7 +11,8 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(gte_atom_c);
#pragma region MACs (Mips Atom Components) #pragma region MACs (Mips Atom Components)
/* Words: 3; Loads 3 S2 indices from the face array */ /* Words: 3; Loads 3 S2 indices from the face array */
FI_ Slice_MipsCode ac_load_tri_indices(AtomBuilder_R ab, U4 r_face_cusor, U4 r_i0, U4 r_i1, U4 r_i2) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_load_tri_indices(AtomBuilder_R ab, U4 r_face_cusor, U4 r_i0, U4 r_i1, U4 r_i2)
atom_dbg_skip MipsAtomComp_Proc_(ab, {
load_half_u(r_i0, r_face_cusor, 0 * S_(S2)), load_half_u(r_i0, r_face_cusor, 0 * S_(S2)),
load_half_u(r_i1, r_face_cusor, 1 * S_(S2)), load_half_u(r_i1, r_face_cusor, 1 * S_(S2)),
load_half_u(r_i2, r_face_cusor, 2 * S_(S2)), load_half_u(r_i2, r_face_cusor, 2 * S_(S2)),
@@ -54,21 +55,34 @@ FI_ Slice_MipsCode ac_gte_store_g4_p3(AtomBuilder_R ab, U4 r_primitive_cursor) a
* Stage 2 of normalize consumes these directly. * Stage 2 of normalize consumes these directly.
* Words: 8. Clobbers: IR1/2/3, MAC1/2/3. Uses gte_cmdw_sqr (sf=0, lm=1). */ * Words: 8. Clobbers: IR1/2/3, MAC1/2/3. Uses gte_cmdw_sqr (sf=0, lm=1). */
FI_ Slice_MipsCode ac_gte_sqr_v3(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, U4 r_sq_x, U4 r_sq_y, U4 r_sq_z) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_gte_sqr_v3(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, U4 r_sq_x, U4 r_sq_y, U4 r_sq_z) atom_dbg_skip MipsAtomComp_Proc_(ab, {
gte_mv_to_data_r(r_sx, C2_IR1), mac_gte_sqr_v3s4(r_sx, r_sy, r_sz, nop),
gte_mv_to_data_r(r_sy, C2_IR2),
gte_mv_to_data_r(r_sz, C2_IR3),
nop, gte_cmdw_sqr,
gte_mv_from_data_r(r_sq_x, C2_MAC1), gte_mv_from_data_r(r_sq_x, C2_MAC1),
gte_mv_from_data_r(r_sq_y, C2_MAC2), gte_mv_from_data_r(r_sq_y, C2_MAC2),
gte_mv_from_data_r(r_sq_z, C2_MAC3), gte_mv_from_data_r(r_sq_z, C2_MAC3),
}) })
/* ─── SQR FIRE — mtc2 3 GPRs into IR1/IR2/IR3, then fire SQR. ───
* The SQR command always squares IR1/IR2/IR3 — those C2 registers are fixed.
* The GPRs holding the source vector are caller-determined.
* Words: 5 (3 mtc2 + 1 nop hazard + 1 cmd). */
FI_ Slice_MipsCode ac_gte_sqr_v3s4(AtomBuilder_R ab, Reg r_sx, Reg r_sy, Reg r_sz, MipsCode nop_slot)
atom_dbg_skip MipsAtomComp_Proc_(ab, {
gte_mv_to_data_r(r_sx, C2_IR1),
gte_mv_to_data_r(r_sy, C2_IR2),
gte_mv_to_data_r(r_sz, C2_IR3),
nop_slot, gte_cmdw_sqr,
})
/* ─── STAGE 4 of normalize: mtc2 IR0..3 + GPF + mfc2 MAC + srav finalize ─── /* ─── STAGE 4 of normalize: mtc2 IR0..3 + GPF + mfc2 MAC + srav finalize ───
* Reusable standalone — given an IR0 = 1/|v| estimate (typically from a sqrtbl lookup) and a shift count * Reusable standalone — given an IR0 = 1/|v| estimate (typically from a sqrtbl lookup) and a shift count
* (typically (31 - LZCR)/2), multiplies IR0*IR[i] via GPF and shifts right to produce the normalized output. * (typically (31 - LZCR)/2), multiplies IR0*IR[i] via GPF and shifts right to produce the normalized output.
* Used standalone for "scale vector by scalar". * Used standalone for "scale vector by scalar".
* Words: 11. Clobbers: IR0..3, MAC1..3. Uses gte_cmdw_gpf (sf=0, lm=0). */ * Words: 11. Clobbers: IR0..3, MAC1..3. Uses gte_cmdw_gpf (sf=0, lm=0). */
FI_ Slice_MipsCode ac_gte_gpf_scale(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, U4 r_recip_est, U4 r_shift, U4 r_dx, U4 r_dy, U4 r_dz) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_gte_gpf_scale(AtomBuilder_R ab,
U4 r_sx, U4 r_sy, U4 r_sz,
U4 r_recip_est, U4 r_shift,
U4 r_dx, U4 r_dy, U4 r_dz)
atom_dbg_skip MipsAtomComp_Proc_(ab, {
gte_mv_to_data_r(r_recip_est, C2_IR0), gte_mv_to_data_r(r_recip_est, C2_IR0),
gte_mv_to_data_r(r_sx, C2_IR1), gte_mv_to_data_r(r_sx, C2_IR1),
gte_mv_to_data_r(r_sy, C2_IR2), gte_mv_to_data_r(r_sy, C2_IR2),
@@ -100,6 +114,79 @@ FI_ Slice_MipsCode ac_trans_mt3s3s4(AtomBuilder_R ab
store_word(r_t2, r_mtx, O_(MT3_S2S4,t[2])), store_word(r_t2, r_mtx, O_(MT3_S2S4,t[2])),
}) })
/* ─── LZCR ROUND EVEN + HALF-SHIFT ───
* Takes the raw LZCR leading-zero/ones count (from mfc2 C2_LZCR, range 1..32
* per PSX-SPX cop2r31) and the |v|² sum (in r_mag_sq from the MAC1+MAC2+MAC3
* add). Produces:
* r_shift ← LZCR rounded down to even (clear bit 0)
* r_mag_sq_copy ← |v|² sum (moved out of r_mag_sq before it's overwritten)
* r_mag_sq ← (31 - even_LZCR) / 2 = the final srav/GPF shift amount
*
* Rounding to even ensures (31 - LZCR) is always odd, so the >> 1 division
* is consistent — no 0.5 loss. The caller branches on LZCR < 24 to decide
* left-shift vs right-shift of r_mag_sq_copy, then saves the shift count.
*
* Note: C2_LZCR (cop2r31) is a fixed read-only C2 data register — the caller
* must read it via mfc2 from C2_LZCR; there is no register choice at the
* hardware level. Only the GPR that holds the result is caller-determined. */
FI_ Slice_MipsCode ac_lzcr_round_even_half_shift(AtomBuilder_R ab,
U4 r_shift,
U4 r_mag_sq,
U4 r_mag_sq_copy
)
atom_dbg_skip MipsAtomComp_Proc_(ab, {
and_i(r_shift, r_shift, gte_lzcr_even_mask),
or_u(r_mag_sq_copy, r_mag_sq, 0),
li_s(r_mag_sq, 31),
sub_s(r_mag_sq, r_mag_sq, r_shift),
shift_aright(r_mag_sq, r_mag_sq, 1),
})
FI_ Slice_MipsCode ac_shift_aright_var_v3(AtomBuilder_R ab
, Reg rd_v0, Reg rd_v1, Reg rd_v2
, Reg rs_v0, Reg rs_v1, Reg rs_v2
, Reg r_shift)
MipsAtomComp_Proc_(ab, {
shift_aright_var(rd_v0, rs_v0, r_shift),
shift_aright_var(rd_v1, rs_v1, r_shift),
shift_aright_var(rd_v2, rs_v2, r_shift),
})
FI_ Slice_MipsCode ac_shift_aright_var_v3_self(AtomBuilder_R ab
, Reg rds_v0, Reg rds_v1, Reg rds_v2
, Reg r_shift)
MipsAtomComp_Proc_(ab, {
shift_aright_var(rds_v0, rds_v0, r_shift),
shift_aright_var(rds_v1, rds_v1, r_shift),
shift_aright_var(rds_v2, rds_v2, r_shift),
})
FI_ Slice_MipsCode ac_gte_general_purpose_interopolation(AtomBuilder_R ab
, Reg to_ir0, Reg to_ir1, Reg to_ir2, Reg to_ir3
, Reg fr_mac1, Reg fr_mac2, Reg fr_mac3
, MipsCode nop_slot1, MipsCode nop_slot2)
MipsAtomComp_Proc_(ab, {
gte_mv_to_data_r(to_ir0, C2_IR0),
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) */
LdSlot_ nop_slot1,
LdSlot_ nop_slot2,
gte_cmdw_gpf,
gte_mv_from_data_r(fr_mac1, C2_MAC1),
gte_mv_from_data_r(fr_mac2, C2_MAC2),
gte_mv_from_data_r(fr_mac3, C2_MAC3),
})
FI_ Slice_MipsCode gte_mv_from_data_r_mac123(AtomBuilder_R ab
, Reg fr_mac1, Reg fr_mac2, Reg fr_mac3
)
MipsAtomComp_Proc_(ab, {
gte_mv_from_data_r(fr_mac1, C2_MAC1),
gte_mv_from_data_r(fr_mac2, C2_MAC2),
gte_mv_from_data_r(fr_mac3, C2_MAC3),
})
#pragma endregion MACs (Mips Atom Components) #pragma endregion MACs (Mips Atom Components)
#pragma region Atom Procs #pragma region Atom Procs
@@ -186,7 +273,7 @@ internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
* r_mac1_scratch : MAC1 result scratch (also holds aligned |v|² in stage 3) * r_mac1_scratch : MAC1 result scratch (also holds aligned |v|² in stage 3)
* r_mac2_scratch : MAC2 result scratch → result.x after stage 4 sra * r_mac2_scratch : MAC2 result scratch → result.x after stage 4 sra
* r_recip_est : src.y PRESERVED across stages 1-2 → fed to IR2 in stage 4 → result.y * r_recip_est : src.y PRESERVED across stages 1-2 → fed to IR2 in stage 4 → result.y
* r_lzcr : |v|² sum (stage 2) → shift count (stage 3) → 1/|v| (stage 4 IR0) * r_norm : |v|² sum (stage 2) → half-shift (stage 3) → 1/|v| (stage 4 IR0)
* r_shift : shift count SAVED in stage 3 → consumed by stage 4 srav * r_shift : shift count SAVED in stage 3 → consumed by stage 4 srav
* r_branch_tmp : src.z PRESERVED across stages 1-2 → fed to IR3 in stage 4 → result.z (also sqrtbl base addr) * r_branch_tmp : src.z PRESERVED across stages 1-2 → fed to IR3 in stage 4 → result.z (also sqrtbl base addr)
* *
@@ -203,93 +290,70 @@ internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
*/ */
/* MipsAtom_Proc_ wrapper: declares the static MipsCode[] body, then calls atombuilder_unroll(ab, ...) to copy the encoded instructions into the caller's MipsAtomBuilder arena. */ /* MipsAtom_Proc_ wrapper: declares the static MipsCode[] body, then calls atombuilder_unroll(ab, ...) to copy the encoded instructions into the caller's MipsAtomBuilder arena. */
internal MipsAtom* normalize_v3s4_proc(AtomArena_R aa, U4 r_scratch /* GPR code: scratch base carrier (e.g., R_T4 = R_ResolveScratch) */ internal MipsAtom* normalize_v3s4_proc(AtomArena_R aa, U4 r_scratch /* GPR code: scratch base carrier (e.g., R_T4 = R_ResolveScratch) */
, U4 r_src_offset, U4 r_dst_offset /* GPR codes: PARAMETERIZED offsets (caller passes O_ macros) */ , U4 src_offset, U4 dst_offset /* GPR codes: PARAMETERIZED offsets (caller passes O_ macros) */
, U4 r_src_ptr, U4 r_dst_ptr, U4 r_tmp /* GPR codes: 3 scratch regs (src/dst computed + tmp) */ , Reg r_src_ptr, Reg r_dst_ptr, Reg r_tmp /* GPR codes: 3 scratch regs (src/dst computed + tmp) */
, U4 r_mac1_scratch, U4 r_mac2_scratch /* GPR codes: 2 more: MAC1/MAC2 scratch */ , Reg r_mac1_scratch, Reg r_mac2_scratch /* GPR codes: 2 more: MAC1/MAC2 scratch */
, U4 r_recip_est /* GPR code: |v|² sum + shift-input + sqrtbl[index] */ , Reg r_recip_est /* GPR code: |v|² sum + shift-input + sqrtbl[index] */
, U4 r_lzcr, U4 r_shift /* GPR codes: lzcr + final srav amount */ , Reg r_norm, Reg r_shift /* GPR codes: normalize working reg + final srav amount */
, U4 r_branch_tmp /* GPR code: scratch (shift count, branch target, lookup addr) */ , Reg r_branch_tmp /* GPR code: scratch (shift count, branch target, lookup addr) */
) )
MipsAtom_Proc_(aa, { MipsAtom_Proc_(aa, {
add_si(r_src_ptr, r_scratch, r_src_offset), /* r_src_ptr = &src */ add_si(r_src_ptr, r_scratch, src_offset), /* r_src_ptr = &src */
add_si(r_dst_ptr, r_scratch, r_dst_offset), /* r_dst_ptr = &dst */ // add_si(r_dst_ptr, r_scratch, r_dst_offset), /* r_dst_ptr = &dst */
nop,
/* 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.
* r_tmp holds src.x throughout stages 1-2 — r_mac2_scratch is clobbered to MAC2 in stage 1.5 (line below). */ * r_tmp holds src.x throughout stages 1-2 — r_mac2_scratch is clobbered to MAC2 in stage 1.5 (line below). */
load_word(r_tmp, r_src_ptr, O_(V3_S4,x)), mac_load_v3s4(r_tmp, r_recip_est, r_branch_tmp, r_src_ptr, 0),
load_word(r_recip_est, r_src_ptr, O_(V3_S4,y)),
load_word(r_branch_tmp, r_src_ptr, O_(V3_S4,z)),
nop, /* load-delay */
/* Stage 1: mtc2 src → IR1/2/3, SQR fires. */ /* Stage 1: mtc2 src → IR1/2/3, SQR fires. */
gte_mv_to_data_r(r_tmp, C2_IR1), LdSlot_ mac_gte_sqr_v3s4(r_tmp, r_recip_est, r_branch_tmp, LdSlot_ nop),
gte_mv_to_data_r(r_recip_est, C2_IR2),
gte_mv_to_data_r(r_branch_tmp, C2_IR3),
nop, gte_cmdw_sqr,
/* Stage 2: mfc2 MAC1/2/3, sum, mtc2 LZCS. */ /* Stage 2: mfc2 MAC1/2/3, sum, mtc2 LZCS. */
gte_mv_from_data_r(r_mac1_scratch, C2_MAC1), mac_gte_mv_from_data_r_mac123(r_mac1_scratch, r_mac2_scratch, r_norm), LdSlot_ nop,
gte_mv_from_data_r(r_mac2_scratch, C2_MAC2), add_u_self( r_norm, r_mac1_scratch),
gte_mv_from_data_r(r_lzcr, C2_MAC3), add_u_self( r_norm, r_mac2_scratch),
nop, gte_mv_to_data_r( r_norm, C2_LZCS), LdSlot_ nop2,
add_u(r_lzcr, r_lzcr, r_mac2_scratch), gte_mv_from_data_r(r_shift, C2_LZCR), LdSlot_ nop,
add_u(r_lzcr, r_lzcr, r_mac1_scratch),
gte_mv_to_data_r(r_lzcr, C2_LZCS),
nop2,
gte_mv_from_data_r(r_shift, C2_LZCR),
nop,
/* Stage 3: compute srav amount (r_lzcr) + align |v|² to bit 24. /* Stage 3: round LZCR to even, compute half-shift, align |v|² to bit 24.
* IMPORTANT: the sllv/srav below writes the aligned |v|² to r_mac1_scratch (NOT r_lzcr), * r_norm holds |v|² sum; r_shift holds the LZCR count from mfc2.
* so r_lzcr retains the shift count all the way to the start of stage 4. * After the component: r_shift = even(LZCR), r_norm = half-shift, r_mac1_scratch = |v|². */
*/ mac_lzcr_round_even_half_shift(r_shift, r_norm, r_mac1_scratch),
and_i( r_shift, r_shift, -2),
or_u(r_mac1_scratch, r_lzcr, 0), /* FIX B: save sum before clobbering r_lzcr with shift count */
li_s( r_lzcr, 31),
sub_s( r_lzcr, r_lzcr, r_shift),
shift_aright(r_lzcr, r_lzcr, 1),
/* r_branch_tmp = LZCR - 24 (overwrites r_branch_tmp; src.z no longer needed after SQR) */ /* r_branch_tmp = LZCR - 24 (overwrites r_branch_tmp; src.z no longer needed after SQR) */
add_si( r_branch_tmp, r_shift, -24), add_si( r_branch_tmp, r_shift, -24),
branch_lt_zero(r_branch_tmp, atom_offset(aligned_done, srav_path)), nop, /* FIX A: bltz → srav_path (LZCR<24 path) */ branch_lt_zero(r_branch_tmp, atom_offset(aligned_done, srav_path)), BdSlot_ nop, /* bltz → srav_path (LZCR < 24 path) */
jump_rel(atom_offset(srav_path, aligned_done)), /* FIX A: b → aligned_done (LZCR>=24 path) */ jump_rel(atom_offset(srav_path, aligned_done)), /* b → aligned_done (LZCR >= 24 path) */
shift_lleft_var(r_mac1_scratch, r_mac1_scratch, r_branch_tmp), /* FIX B: src=sum (r_mac1_scratch), dst=same */ BdSlot_ shift_lleft_var(r_mac1_scratch, r_mac1_scratch, r_branch_tmp), /* src=sum (r_mac1_scratch), dst=same */
atom_label(srav_path) atom_label(srav_path)
li_s( r_branch_tmp, 24), li_s( r_branch_tmp, 24),
sub_s(r_branch_tmp, r_branch_tmp, r_shift), sub_s(r_branch_tmp, r_branch_tmp, r_shift),
shift_aright_var(r_mac1_scratch, r_mac1_scratch, r_branch_tmp), /* FIX B: src=sum (r_mac1_scratch), dst=same */ shift_aright_var(r_mac1_scratch, r_mac1_scratch, r_branch_tmp), /* src=sum (r_mac1_scratch), dst=same */
atom_label(aligned_done) atom_label(aligned_done)
/* Save the shift count to r_shift before the next 5 instructions overwrite r_lzcr // Save the shift count to r_shift before the next 5 instructions overwrite r_norm (the sqrtbl lookup loads 1/|v| into r_norm, which becomes IR0 in stage 4).
* (the sqrtbl lookup loads 1/|v| into r_lzcr, which becomes IR0 in stage 4). */ or_u(r_shift, r_norm, 0), /* r_shift ← shift count (preserved through stage 4) */
or_u(r_shift, r_lzcr, 0), /* r_shift ← shift count (preserved through stage 4) */
/* r_mac1_scratch holds |v|² aligned (top bit at bit 7). */ /* r_mac1_scratch holds |v|² aligned (top bit at bit 7). */
add_si( r_mac1_scratch, r_mac1_scratch, -64), add_si( r_mac1_scratch, r_mac1_scratch, -64),
shift_lleft(r_mac1_scratch, r_mac1_scratch, 1), shift_lleft(r_mac1_scratch, r_mac1_scratch, 1),
load_upper_i(r_branch_tmp, u4_hi(& gte_normalize_sqr_tbl)), mac_load_word_imm(r_branch_tmp, & gte_normalize_sqr_tbl), add_u_self(r_branch_tmp, r_mac1_scratch),
or_i_self( r_branch_tmp, u4_lo(& gte_normalize_sqr_tbl)), load_half(r_norm, r_branch_tmp, 0), /* r_norm = sqrtbl[aligned-64] = 1/|v| (IR0 in stage 4) */
add_u(r_branch_tmp, r_branch_tmp, r_mac1_scratch),
load_half(r_lzcr, r_branch_tmp, 0), nop, /* r_lzcr = sqrtbl[aligned-64] = 1/|v| (IR0 in stage 4) */
/* FIX bug C: r_branch_tmp held the sqrtbl base+index, NOT src.z. Reload src.z from scratch now that r_branch_tmp is free. */ /* r_branch_tmp held the sqrtbl base+index, NOT src.z. Reload src.z from scratch now that r_branch_tmp is free. */
load_word(r_branch_tmp, r_src_ptr, O_(V3_S4,z)), nop, /* r_branch_tmp = src.z (for IR3 in stage 4) */ LdSlot_ load_word(r_branch_tmp, r_src_ptr, O_(V3_S4,z)), /* r_branch_tmp = src.z (for IR3 in stage 4) */
/* Stage 4: GPF + srav finalize (r_shift = shift count, r_lzcr = 1/|v|). */
gte_mv_to_data_r(r_lzcr, C2_IR0),
gte_mv_to_data_r(r_tmp, 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(r_recip_est, C2_IR2),
gte_mv_to_data_r(r_branch_tmp, C2_IR3), /* IR3 = src.z (reloaded) */
nop2, gte_cmdw_gpf,
gte_mv_from_data_r(r_mac2_scratch, C2_MAC1),
gte_mv_from_data_r(r_recip_est, C2_MAC2),
gte_mv_from_data_r(r_branch_tmp, C2_MAC3),
shift_aright_var(r_mac2_scratch, r_mac2_scratch, r_shift), /* sra by r_shift = (31-LZCR)/2 (saved before sqrtbl lookup) */
shift_aright_var(r_recip_est, r_recip_est, r_shift),
shift_aright_var(r_branch_tmp, r_branch_tmp, r_shift),
/* Stage 4: GPF + srav finalize (r_shift = shift count, r_norm = 1/|v|). */
LdSlot_ mac_gte_general_purpose_interopolation(
r_norm,
r_tmp, /* IR1 = src.x (preserved in r_tmp — r_mac2_scratch was clobbered to MAC2 in stage 1.5) */
r_recip_est,
r_branch_tmp, /* IR3 = src.z (reloaded) */
r_mac2_scratch, r_recip_est, r_branch_tmp,
LdSlot_ add_si(r_dst_ptr, r_scratch, dst_offset), // pre-laoding destination to register here.
LdSlot_ nop
),
/* sra by r_shift = (31-LZCR)/2 (saved before sqrtbl lookup) */
mac_shift_aright_var_v3_self(r_mac2_scratch, r_recip_est, r_branch_tmp, r_shift),
/* Store result.x/y/z to r_dst_ptr (caller-determined dst address). */ /* Store result.x/y/z to r_dst_ptr (caller-determined dst address). */
store_word(r_mac2_scratch, r_dst_ptr, O_(V3_S4,x)), mac_store_v3s4(r_mac2_scratch, r_recip_est, r_branch_tmp, r_dst_ptr, 0),
store_word(r_recip_est, r_dst_ptr, O_(V3_S4,y)),
store_word(r_branch_tmp, r_dst_ptr, O_(V3_S4,z)),
mac_yield() mac_yield()
}) })
+8
View File
@@ -483,6 +483,14 @@ enum { _C2_TX_SUBS_ = 0
* bits 24-20 = 0x19 (libgte "nonsense SDK command number" signature) */ * bits 24-20 = 0x19 (libgte "nonsense SDK command number" signature) */
#define gte_cmdw_gpf (gte_cmd_base | enc_gte_cmd(gte_cmd_gpf) | gte_cmdw_gpf_fake_sig) #define gte_cmdw_gpf (gte_cmd_base | enc_gte_cmd(gte_cmd_gpf) | gte_cmdw_gpf_fake_sig)
/* Mask to round LZCR (leading-zero/ones count, range 1..32 per PSX-SPX cop2r31)
* down to even. The normalize_v3s4 half-shift logic computes (31 - LZCR) >> 1;
* clearing bit 0 ensures the subtraction result is always odd,
* so the >> 1 division is consistent (no 0.5 loss). */
enum {
gte_lzcr_even_mask = 0xFFFE, /* all bits except bit 0 */
};
#define gte_cmdw_rotate_translate_perspective_single gte_cmdw_rtps #define gte_cmdw_rotate_translate_perspective_single gte_cmdw_rtps
#define gte_cmdw_rotate_translate_perspective_triple gte_cmdw_rtpt #define gte_cmdw_rotate_translate_perspective_triple gte_cmdw_rtpt
/* RGA(Lengyel): RTPS/RTPT consume the matrix expansion of a rigid transformation (rotation matrix + translation vector) loaded into the RT/TR control registers. /* RGA(Lengyel): RTPS/RTPT consume the matrix expansion of a rigid transformation (rotation matrix + translation vector) loaded into the RT/TR control registers.
+8
View File
@@ -318,7 +318,10 @@ enum { _BitOffsets = 0
#define load_half(rt, base, off) enc_i(op_lh, (base), (rt), (off)) #define load_half(rt, base, off) enc_i(op_lh, (base), (rt), (off))
#define load_byte_u(rt, base, off) enc_i(op_lbu, (base), (rt), (off)) #define load_byte_u(rt, base, off) enc_i(op_lbu, (base), (rt), (off))
#define load_half_u(rt, base, off) enc_i(op_lhu, (base), (rt), (off)) #define load_half_u(rt, base, off) enc_i(op_lhu, (base), (rt), (off))
#define LdSlot_
#define store_word(rt, base, off) enc_i(op_sw, (base), (rt), (off)) #define store_word(rt, base, off) enc_i(op_sw, (base), (rt), (off))
#define add_ui(rt, rs, imm) enc_i(op_addiu, (rs), (rt), (imm)) #define add_ui(rt, rs, imm) enc_i(op_addiu, (rs), (rt), (imm))
#define and_i(rt, rs, imm) enc_i(op_andi, (rs), (rt), (imm)) #define and_i(rt, rs, imm) enc_i(op_andi, (rs), (rt), (imm))
// #define and_si and_i // #define and_si and_i
@@ -379,6 +382,9 @@ enum { _BitOffsets = 0
*/ */
#define jump(off) enc_i(op_j, R_0, R_0, (off)) #define jump(off) enc_i(op_j, R_0, R_0, (off))
// Annotate an instruction as filling a branch-delay slot.
#define BdSlot_
/* jump_rel off — unconditional relative jump (the within-atom-safe `jump`). /* jump_rel off — unconditional relative jump (the within-atom-safe `jump`).
* MIPS I R3000A has no "branch always" opcode. The idiom for an unconditional relative jump is `beq $0, $0, off`. */ * MIPS I R3000A has no "branch always" opcode. The idiom for an unconditional relative jump is `beq $0, $0, off`. */
#define jump_rel(off) branch_equal(R_0, R_0, (off)) #define jump_rel(off) branch_equal(R_0, R_0, (off))
@@ -411,6 +417,7 @@ enum { _BitOffsets = 0
#define div_s(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_div) #define div_s(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_div)
#define div_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_divu) #define div_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_divu)
// TODO(Ed): Change convention of 'self' to ds for (destination is source)?
#define add_u_self(rd_rs, rt) add_u(rd_rs, rd_rs, rt) #define add_u_self(rd_rs, rt) add_u(rd_rs, rd_rs, rt)
/* --- Arithmetic I-type (immediate) --- */ /* --- Arithmetic I-type (immediate) --- */
@@ -458,6 +465,7 @@ enum { _BitOffsets = 0
// li_s — load signed 16-bit immediate into GPR (addiu rt, $0, imm — sign-extends). // li_s — load signed 16-bit immediate into GPR (addiu rt, $0, imm — sign-extends).
#define li_s(rt, imm) add_ui((rt), R_0, (imm)) #define li_s(rt, imm) add_ui((rt), R_0, (imm))
// #define load_imm_s(rt, imm) add_ui((rt), R_0, (imm))
#define load_imm_1w(rt, imm) add_ui((rt), R_0, (imm)) #define load_imm_1w(rt, imm) add_ui((rt), R_0, (imm))
#define load_imm_1w_s0(rt, imm) add_si((rt)), R_0, (imm)) #define load_imm_1w_s0(rt, imm) add_si((rt)), R_0, (imm))
+2 -6
View File
@@ -511,12 +511,8 @@ internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa
* Pool cost: r_look_at (1) + r_scratch (carrier) + r_off_ptr + 1 clobber = 4 GPRs. * Pool cost: r_look_at (1) + r_scratch (carrier) + r_off_ptr + 1 clobber = 4 GPRs.
*/ */
I_ MipsAtom* resolve_look_at__trans_matrix_proc(AtomArena_R aa I_ MipsAtom* resolve_look_at__trans_matrix_proc(AtomArena_R aa
, U4 r_look_at , U4 r_look_at, U4 r_scratch, U4 r_off_ptr
, U4 r_scratch , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2
, U4 r_off_ptr
, U4 r_tmp0
, U4 r_tmp1
, U4 r_tmp2
) MipsAtom_Proc_(aa, { ) MipsAtom_Proc_(aa, {
/* Pop look_at* from tape. */ /* Pop look_at* from tape. */
// load_word(r_Vlook_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)), // load_word(r_Vlook_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)),
+10 -10
View File
@@ -184,7 +184,7 @@ internal void resolve_look_at_init(void) {
U4 r_mac1 = R_T3; U4 r_mac1 = R_T3;
U4 r_mac2 = R_T5; U4 r_mac2 = R_T5;
U4 r_recip = R_T6; U4 r_recip = R_T6;
U4 r_lzcr = R_T7; U4 r_norm = R_T7;
U4 r_shift = R_V0; U4 r_shift = R_V0;
U4 r_branch = R_V1; U4 r_branch = R_V1;
// tb_emit_( // tb_emit_(
@@ -192,7 +192,7 @@ internal void resolve_look_at_init(void) {
R_ResolveScratch, R_ResolveScratch,
r_src_offset, r_dst_offset, r_src_offset, r_dst_offset,
r_src_ptr, r_dst_ptr, r_tmp, r_src_ptr, r_dst_ptr, r_tmp,
r_mac1, r_mac2, r_recip, r_lzcr, r_mac1, r_mac2, r_recip, r_norm,
r_shift, r_branch); r_shift, r_branch);
// ); // );
@@ -217,14 +217,14 @@ internal void resolve_look_at_init(void) {
U4 r_mac1_3 = R_T3; U4 r_mac1_3 = R_T3;
U4 r_mac2_3 = R_T5; U4 r_mac2_3 = R_T5;
U4 r_recip_3 = R_T6; U4 r_recip_3 = R_T6;
U4 r_lzcr_3 = R_T7; U4 r_norm_3 = R_T7;
U4 r_shift_3 = R_V0; U4 r_shift_3 = R_V0;
U4 r_branch_3 = R_V1; U4 r_branch_3 = R_V1;
smem.resolve_look_at_atom_addrs[3] = normalize_v3s4_proc(& ab, smem.resolve_look_at_atom_addrs[3] = normalize_v3s4_proc(& ab,
R_ResolveScratch, R_ResolveScratch,
r_src_offset_3, r_dst_offset_3, r_src_offset_3, r_dst_offset_3,
r_src_ptr_3, r_dst_ptr_3, r_tmp_3, r_src_ptr_3, r_dst_ptr_3, r_tmp_3,
r_mac1_3, r_mac2_3, r_recip_3, r_lzcr_3, r_mac1_3, r_mac2_3, r_recip_3, r_norm_3,
r_shift_3, r_branch_3); r_shift_3, r_branch_3);
/* === ATOM 4: cross uz×ux→up === */ /* === ATOM 4: cross uz×ux→up === */
@@ -248,14 +248,14 @@ internal void resolve_look_at_init(void) {
U4 r_mac1_5 = R_T3; U4 r_mac1_5 = R_T3;
U4 r_mac2_5 = R_T5; U4 r_mac2_5 = R_T5;
U4 r_recip_5 = R_T6; U4 r_recip_5 = R_T6;
U4 r_lzcr_5 = R_T7; U4 r_norm_5 = R_T7;
U4 r_shift_5 = R_V0; U4 r_shift_5 = R_V0;
U4 r_branch_5 = R_V1; U4 r_branch_5 = R_V1;
smem.resolve_look_at_atom_addrs[5] = normalize_v3s4_proc(& ab, smem.resolve_look_at_atom_addrs[5] = normalize_v3s4_proc(& ab,
R_ResolveScratch, R_ResolveScratch,
r_src_offset_5, r_dst_offset_5, r_src_offset_5, r_dst_offset_5,
r_src_ptr_5, r_dst_ptr_5, r_tmp_5, r_src_ptr_5, r_dst_ptr_5, r_tmp_5,
r_mac1_5, r_mac2_5, r_recip_5, r_lzcr_5, r_mac1_5, r_mac2_5, r_recip_5, r_norm_5,
r_shift_5, r_branch_5); r_shift_5, r_branch_5);
/* === ATOM 6a: populate (m[][] from ux/uy/uz, t[]=0) === */ /* === ATOM 6a: populate (m[][] from ux/uy/uz, t[]=0) === */
@@ -370,10 +370,10 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
tb_data_(state, & smem.pad[0]); tb_data_(state, & smem.pad[0]);
tb_data_(cam, & smem.cam); tb_data_(cam, & smem.cam);
tb_emit_(pad_input_cube_rotation); // tb_emit_(pad_input_cube_rotation);
tb_data_(state, & smem.pad[0]); // tb_data_(state, & smem.pad[0]);
tb_data_(cube_rot, & smem.cube.rot); // tb_data_(cube_rot, & smem.cube.rot);
tb_data_(floor_rot, & smem.floor.rot); // tb_data_(floor_rot, & smem.floor.rot);
} }
} }
+2
View File
@@ -1589,6 +1589,8 @@ M.INSTRUCTION_LATENCY = {
["atom_bind"] = 0, ["atom_bind"] = 0,
["atom_reads"] = 0, ["atom_reads"] = 0,
["atom_writes"] = 0, ["atom_writes"] = 0,
["BdSlot_"] = 0,
["LdSlot_"] = 0,
} }
-- Default cycle cost for unknown macros. -- Default cycle cost for unknown macros.