From 5c9c61720fac1627ada0bac0b132b5071dd2dcf6 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 13 Aug 2026 21:42:06 -0400 Subject: [PATCH] Redesign: Not making local var in MipsAtom_Proc_ or MipsAtomComp_Proc_ have sym tied to proc name. Adjusted parser as well base do that. --- code/duffle/gen/macs.h | 2 + code/duffle/gp.atom.c | 18 ++-- code/duffle/gte.atom.c | 18 ++-- code/duffle/lottes_tape.h | 21 ++-- code/duffle/math.atom.c | 12 +-- code/duffle/mips.atom.c | 11 +- code/duffle/pad.atom.c | 9 +- code/hello_camera/hello_camera.atom.c | 16 +-- code/hello_joypad/hello_joypad.atom.c | 4 +- scripts/duffle.lua | 149 +++++++++++++++++++++++++- scripts/passes/components.lua | 43 ++------ scripts/passes/scan_source.lua | 25 ++++- 12 files changed, 236 insertions(+), 92 deletions(-) diff --git a/code/duffle/gen/macs.h b/code/duffle/gen/macs.h index 325aa13..43297b2 100644 --- a/code/duffle/gen/macs.h +++ b/code/duffle/gen/macs.h @@ -190,6 +190,7 @@ WORD_COUNT(mac_gte_gpf_scale, 13) , store_word(r_t2, r_mtx, O_(MT3_S2S4,t[2])) WORD_COUNT(mac_trans_mt3s3s4, 6) +/* atom_dbg_skip */ #define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \ mac_load_word_imm(reg_transfer, cmd) \ , store_word( reg_transfer, reg_base, port) @@ -214,6 +215,7 @@ WORD_COUNT(mac_pack_color_word, 3) mac_pack_color_word(r_base, O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) WORD_COUNT(mac_format_f3_color, 3) +/* atom_dbg_skip */ #define mac_format_g4_color(r_prim_cursor, r0, g0, b0, r1, g1, b1, r2, g2, b2, r3, g3, b3) \ mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c0), gp0_cmd_poly_g4, r0,g0,b0) \ , mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c1), 0, r1,g1,b1) \ diff --git a/code/duffle/gp.atom.c b/code/duffle/gp.atom.c index d40cc4a..3cb1c99 100644 --- a/code/duffle/gp.atom.c +++ b/code/duffle/gp.atom.c @@ -8,34 +8,40 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(gp_atom_c); #pragma region MACs (Mips Atom Components) +atom_dbg_skip FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U4 cmd, U4 reg_transfer, U4 reg_base, U2 port) -MipsAtomComp_Proc_(ac_gcmd_push, ab, { +MipsAtomComp_Proc_(ab, { mac_load_word_imm(reg_transfer, cmd), store_word( reg_transfer, reg_base, port), }) -FI_ Slice_MipsCode ac_store_rgb8(AtomBuilder_R ab, U1 rr, U1 rg, U1 rb, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ac_store_rgb8, ab, { +atom_dbg_skip +FI_ Slice_MipsCode ac_store_rgb8(AtomBuilder_R ab, U1 rr, U1 rg, U1 rb, U4 base, U4 offset) +MipsAtomComp_Proc_(ab, { store_byte(rr, base, offset + O_(RGB8,r)), store_byte(rg, base, offset + O_(RGB8,g)), store_byte(rb, base, offset + O_(RGB8,b)), }) +atom_dbg_skip FI_ Slice_MipsCode ac_pack_color_word(AtomBuilder_R ab, U4 r_base, U4 off, U4 cmd, U1 r, U1 g, U1 b) -atom_dbg_skip MipsAtomComp_Proc_(ac_pack_color_word, ab, { +MipsAtomComp_Proc_(ab, { load_upper_i(R_AT, (cmd) << 8 | (b)), or_i_self( R_AT, ((g) << 8) | (r)), store_word( R_AT, r_base, (off)), }) +atom_dbg_skip FI_ Slice_MipsCode ac_format_f3_color(AtomBuilder_R ab, U4 r_base, U1 r, U1 g, U1 b) -atom_dbg_skip MipsAtomComp_Proc_(ac_format_f3_color, ab, { mac_pack_color_word(r_base, O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) }) +MipsAtomComp_Proc_(ab, { mac_pack_color_word(r_base, O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) }) +atom_dbg_skip FI_ Slice_MipsCode ac_format_g4_color(AtomBuilder_R ab, U4 r_prim_cursor, U1 r0, U1 g0, U1 b0, U1 r1, U1 g1, U1 b1, U1 r2, U1 g2, U1 b2, U1 r3, U1 g3, U1 b3) -MipsAtomComp_Proc_(ac_format_g4_color, ab, { +MipsAtomComp_Proc_(ab, { mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c0), gp0_cmd_poly_g4, r0,g0,b0), mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c1), 0, r1,g1,b1), mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c2), 0, r2,g2,b2), @@ -43,7 +49,7 @@ MipsAtomComp_Proc_(ac_format_g4_color, ab, { }) /* Words: 11; Correctly inserts a primitive into the Ordering Table linked list. */ -I_ Slice_MipsCode ac_insert_ot_tag(AtomBuilder_R ab, U4 r_ot_base, U4 r_prim_cursor, U4 poly_size) MipsAtomComp_Proc_(ac_insert_ot_tag, ab, { +I_ Slice_MipsCode ac_insert_ot_tag(AtomBuilder_R ab, U4 r_ot_base, U4 r_prim_cursor, U4 poly_size) MipsAtomComp_Proc_(ab, { shift_lleft( R_T1, R_T1, S_(U4)/2), // T1 = otz * S_(U4) (otz arg is implicit R_T1) add_u_self( R_T1, r_ot_base), // T1 = & OrderingTable[OTZ] load_word( R_AT, R_T1, O_(PolyTag,code)), // AT = old_ot_head diff --git a/code/duffle/gte.atom.c b/code/duffle/gte.atom.c index eed8df0..0a82023 100644 --- a/code/duffle/gte.atom.c +++ b/code/duffle/gte.atom.c @@ -11,7 +11,7 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(gte_atom_c); #pragma region MACs (Mips Atom Components) /* 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_(ac_load_tri_indices, 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_i1, r_face_cusor, 1 * S_(S2)), load_half_u(r_i2, r_face_cusor, 2 * S_(S2)), @@ -19,14 +19,14 @@ FI_ Slice_MipsCode ac_load_tri_indices(AtomBuilder_R ab, U4 r_face_cusor, U4 r_i /* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3. * PIPELINE: post-RTPT (SXY0=v0.screen, SXY1=v1.screen, SXY2=v2.screen). */ -FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ac_gte_store_f3, ab, { +FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, { gte_sw(C2_SXY0, r_primitive_cursor, O_(Poly_F3,p0)), gte_sw(C2_SXY1, r_primitive_cursor, O_(Poly_F3,p1)), gte_sw(C2_SXY2, r_primitive_cursor, O_(Poly_F3,p2)), }) /* Words: 18; Translates indices to vertex addresses and pushes them to GTE */ -I_ Slice_MipsCode ac_gte_load_tri_verts(AtomBuilder_R ab, U4 r_vert_base, U4 r_v0, U4 r_v1, U4 r_v2) atom_dbg_skip MipsAtomComp_Proc_(ac_gte_load_tri_verts, ab, { +I_ Slice_MipsCode ac_gte_load_tri_verts(AtomBuilder_R ab, U4 r_vert_base, U4 r_v0, U4 r_v1, U4 r_v2) atom_dbg_skip MipsAtomComp_Proc_(ab, { shift_lleft(R_AT, r_v0, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), shift_lleft(R_AT, r_v1, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1), shift_lleft(R_AT, r_v2, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2), @@ -37,7 +37,7 @@ I_ Slice_MipsCode ac_gte_load_tri_verts(AtomBuilder_R ab, U4 r_vert_base, U4 r_v * PIPELINE: post-RTPT, pre-RTPS (SXY0=v0.screen, SXY1=v1.screen, SXY2=v2.screen). * MUST be called BEFORE V3-RTPS, otherwise SXY0/1/2 get overwritten with v3 * (RTPS writes only to SXY2, but to keep the three registers aligned with v0/v1/v2 you must store before RTPS). */ -FI_ Slice_MipsCode ac_gte_store_g4_p012(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ac_gte_store_g4_p012, ab, { +FI_ Slice_MipsCode ac_gte_store_g4_p012(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, { gte_sw(C2_SXY0, r_primitive_cursor, O_(Poly_G4,p0)), gte_sw(C2_SXY1, r_primitive_cursor, O_(Poly_G4,p1)), gte_sw(C2_SXY2, r_primitive_cursor, O_(Poly_G4,p2)), @@ -47,13 +47,13 @@ FI_ Slice_MipsCode ac_gte_store_g4_p012(AtomBuilder_R ab, U4 r_primitive_cursor) * PIPELINE: post-RTPS (SXY2 holds v3.screen because RTPS writes its single-vertex result to SXY2; * SXY0 still holds v0.screen from the earlier RTPT. */ -FI_ Slice_MipsCode ac_gte_store_g4_p3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ac_gte_store_g4_p3, ab, { gte_sw(C2_SXY2, r_primitive_cursor, O_(Poly_G4,p3)) }) +FI_ Slice_MipsCode ac_gte_store_g4_p3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, { gte_sw(C2_SXY2, r_primitive_cursor, O_(Poly_G4,p3)) }) /* ─── STAGE 1 of normalize: SQR + mfc2 MAC1/2/3 ─── * Emits squared magnitude per component (in MAC1/2/3) into caller-provided scratch regs. * Stage 2 of normalize consumes these directly. * 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_(ac_gte_sqr_v3, 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), gte_mv_to_data_r(r_sy, C2_IR2), gte_mv_to_data_r(r_sz, C2_IR3), @@ -68,7 +68,7 @@ FI_ Slice_MipsCode ac_gte_sqr_v3(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, U4 * (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". * 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_(ac_gte_gpf_scale, 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_sx, C2_IR1), gte_mv_to_data_r(r_sy, C2_IR2), @@ -91,7 +91,7 @@ FI_ Slice_MipsCode ac_gte_gpf_scale(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, FI_ Slice_MipsCode ac_trans_mt3s3s4(AtomBuilder_R ab , U4 r_mtx, U4 r_off , U4 r_t0, U4 r_t1, U4 r_t2 -) MipsAtomComp_Proc_(ac_trans_mt3s3s4, ab, { +) MipsAtomComp_Proc_(ab, { load_word(r_t0, r_off, O_(V3_S4,x)), load_word(r_t1, r_off, O_(V3_S4,y)), load_word(r_t2, r_off, O_(V3_S4,z)), @@ -210,7 +210,7 @@ internal MipsAtom* normalize_v3s4_proc(AtomArena_R aa, U4 r_scratch /* GPR code: , U4 r_lzcr, U4 r_shift /* GPR codes: lzcr + final srav amount */ , U4 r_branch_tmp /* GPR code: scratch (shift count, branch target, lookup addr) */ ) -MipsAtom_Proc_(normalize_v3s4, aa, { +MipsAtom_Proc_(aa, { add_si(r_src_ptr, r_scratch, r_src_offset), /* r_src_ptr = &src */ add_si(r_dst_ptr, r_scratch, r_dst_offset), /* r_dst_ptr = &dst */ nop, diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index 3ae0958..78e4714 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -117,10 +117,13 @@ typedef Slice_(MipsAtom); #define MipsAtom_(sym) MipsCode sym [] align_(4) = // Used for atoms with value-args -// FI_ void ac_X(args) MipsAtomComp_Proc_(ac_X, { body }) +// internal MipsAtom* X_proc(AtomArena_R aa, args) MipsAtom_Proc_(X, aa, { body }) // expands to: -// FI_ void ac_X(args) { MipsCode ac_X[] align_(4) = { body }; return ac_X; } -#define MipsAtom_Proc_(sym, aa, ...) { MipsCode sym [] align_(4) = __VA_ARGS__; return atomarena_push(aa, slice_from_array(MipsCode, sym)); } +// internal MipsAtom* X_proc(AtomArena_R aa, args) { MipsCode atom_comp_code[] align_(4) = { body }; return atomarena_push(aa, slice_from_array(MipsCode, atom_comp_code)); } +// The atom name is derived by the Lua metaprogram from the preceding +// `MipsAtom* X_proc(...)` declaration (backward walk from the macro site, +// strips the `_proc` suffix). +#define MipsAtom_Proc_(aa, ...) { MipsCode atom_comp_code[] align_(4) = __VA_ARGS__; return atomarena_push(aa, slice_from_array(MipsCode, atom_comp_code)); } // Used for components with no args (e.g., ac_load_tri_indices) or identifier-args (hardcoded register names). // MipsAtomComp_(ac_X) { body } @@ -129,16 +132,18 @@ typedef Slice_(MipsAtom); #define MipsAtomComp_(sym) MipsCode sym [] align_(4) = // Used for components with value-args (mandatory `ab` (atom-builder) arg). -// FI_ void ac_X(MipsAtomBuilder_R ab, args) MipsAtomComp_Proc_(ac_X, ab, { body }) +// FI_ void ac_X(MipsAtomBuilder_R ab, args) MipsAtomComp_Proc_(ab, { body }) // expands to: // FI_ void ac_X(MipsAtomBuilder_R ab, args) { -// MipsCode ac_X[] align_(4) = { body }; -// atombuilder_unroll(ab, slice_from_array(MipsCode, ac_X)); +// MipsCode atom_comp_code[] align_(4) = { body }; +// atombuilder_push(ab, slice_from_array(MipsCode, atom_comp_code)); // } // The body must NOT include mac_yield() (the parent atom yields). -// Inline-only callers (the generated `mac_` aliases) skip this arg via metaprogram filtering; +// The component name is derived by the Lua metaprogram from the preceding +// `FI_ Slice_MipsCode ac_X(...)` declaration (backward walk from the macro site). +// Inline-only callers (the generated `mac_` aliases) skip the `ab` arg via metaprogram filtering; // escape callers (ac_ invoked as a function) pass a long-lived builder. -#define MipsAtomComp_Proc_(sym, ab, ...) { MipsCode sym [] align_(4) = __VA_ARGS__; atombuilder_push(ab, slice_from_array(MipsCode, sym)); } +#define MipsAtomComp_Proc_(ab, ...) { MipsCode atom_comp_code[] align_(4) = __VA_ARGS__; atombuilder_push(ab, slice_from_array(MipsCode, atom_comp_code)); } /* Line-table anchor: gcc only adds a file to the .debug_line file table when the contains line-numbered content. Files containing only atoms and atom components. diff --git a/code/duffle/math.atom.c b/code/duffle/math.atom.c index f215d18..fc23706 100644 --- a/code/duffle/math.atom.c +++ b/code/duffle/math.atom.c @@ -11,17 +11,17 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(math_atom_c); // FI_ Slice_MipsCode ac_load_imm -FI_ Slice_MipsCode ac_load_v2s2(AtomBuilder_R ab, U4 rs_x, U4 rs_y, U4 r_base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ac_load_v2s2, ab, { +FI_ Slice_MipsCode ac_load_v2s2(AtomBuilder_R ab, U4 rs_x, U4 rs_y, U4 r_base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, { load_half( rs_x, r_base, offset + O_(V3_S2,x)), load_half( rs_y, r_base, offset + O_(V3_S2,y)), }) -FI_ Slice_MipsCode ac_store_v2s2(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ac_store_v2s2, ab, { +FI_ Slice_MipsCode ac_store_v2s2(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, { store_half(rt_x, base, offset + O_(V2_S2,x)), store_half(rt_y, base, offset + O_(V2_S2,y)), }) -FI_ Slice_MipsCode ac_load_v3s4(AtomBuilder_R ab, U4 rs_x, U4 rs_y, U4 rs_z, U4 r_base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ac_load_v3s4, ab, { +FI_ Slice_MipsCode ac_load_v3s4(AtomBuilder_R ab, U4 rs_x, U4 rs_y, U4 rs_z, U4 r_base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, { load_word( rs_x, r_base, offset + O_(V3_S4,x)), load_word( rs_y, r_base, offset + O_(V3_S4,y)), load_word( rs_z, r_base, offset + O_(V3_S4,z)), @@ -30,7 +30,7 @@ FI_ Slice_MipsCode ac_load_v3s4(AtomBuilder_R ab, U4 rs_x, U4 rs_y, U4 rs_z, U4 #define ac_load_p3s4 ac_load_v3s4 #define mac_load_p3s4 mac_load_v3s4 -FI_ Slice_MipsCode ac_store_v3s4(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 rt_z, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ac_store_v3s4, ab, { +FI_ Slice_MipsCode ac_store_v3s4(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 rt_z, U4 base, U4 offset) atom_dbg_skip MipsAtomComp_Proc_(ab, { store_word(rt_x, base, offset + O_(V3_S4,x)), store_word(rt_y, base, offset + O_(V3_S4,y)), store_word(rt_z, base, offset + O_(V3_S4,z)), @@ -39,13 +39,13 @@ FI_ Slice_MipsCode ac_store_v3s4(AtomBuilder_R ab, U4 rt_x, U4 rt_y, U4 rt_z, U4 #define ac_store_p3s4 ac_store_v3s4 #define mac_store_p3s4 mac_store_v3s4 -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_(ac_sub_v3s4, ab, { +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, { sub_s(rds_x, rds_x, rt_x), sub_s(rds_y, rds_y, rt_y), sub_s(rds_z, rds_z, rt_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_(ac_store_rects2, 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_y, base, offset + O_(Rect_S2,y)), store_half(rt_width, base, offset + O_(Rect_S2,width)), diff --git a/code/duffle/mips.atom.c b/code/duffle/mips.atom.c index bc80024..bcb5adb 100644 --- a/code/duffle/mips.atom.c +++ b/code/duffle/mips.atom.c @@ -10,18 +10,11 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(mips_atom_c); #pragma region MACs (Mips Atom Components) -// Tired of this signature: -FI_ Slice_MipsCode ac_load_word_imm(AtomBuilder_R ab, Reg dst, U4 imm) -atom_dbg_skip MipsAtomComp_Proc_(ac_load_word_imm, ab, { +FI_ Slice_MipsCode ac_load_word_imm(AtomBuilder_R ab, Reg dst, U4 imm) +atom_dbg_skip MipsAtomComp_Proc_(ab, { load_upper_i(dst, u4_hi(imm)), or_i_self( dst, u4_lo(imm)), }) -// Can I get away with this instead? -// atom_dbg_skip FI_ Slice_MipsCode -// ac_load_word_imm(AtomBuilder_R ab, Reg dst, U4 imm) MipsAtomComp_Proc_(ab, { -// load_upper_i(dst, u4_hi(imm)), -// or_i_self( dst, u4_lo(imm)), -// }) #pragma endregion MACs (Mips Atom Components) diff --git a/code/duffle/pad.atom.c b/code/duffle/pad.atom.c index d49ae28..f7005de 100644 --- a/code/duffle/pad.atom.c +++ b/code/duffle/pad.atom.c @@ -11,18 +11,19 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(pad_atom_c); #pragma region MACs (Mips Atom Components) -FI_ Slice_MipsCode ac_pad_set_centered_axes(AtomBuilder_R ab, U4 r_state, U4 r_scratch) atom_dbg_skip MipsAtomComp_Proc_(ac_pad_set_centered_axes, ab, { +FI_ Slice_MipsCode ac_pad_set_centered_axes(AtomBuilder_R ab, U4 r_state, U4 r_scratch) atom_dbg_skip MipsAtomComp_Proc_(ab, { load_upper_i(r_scratch, (PadAxis_Centered_Word >> 16) & 0xFFFF), or_i_self( r_scratch, PadAxis_Centered_Word & 0xFFFF), store_word( r_scratch, r_state, O_(PadState,axes)), }) -FI_ Slice_MipsCode ac_pad_set_id_byte(AtomBuilder_R ab, U1 r_state, U1 r_id, U1 id_value) atom_dbg_skip MipsAtomComp_Proc_(ac_pad_set_id_byte, ab, { +FI_ Slice_MipsCode ac_pad_set_id_byte(AtomBuilder_R ab, U1 r_state, U1 r_id, U1 id_value) +atom_dbg_skip MipsAtomComp_Proc_(ab, { add_ui( r_id, R_0, id_value), store_byte(r_id, r_state, O_(PadState,id)), }) -FI_ Slice_MipsCode ac_pad_set_status(AtomBuilder_R ab, U4 r_tmp, U1 r_state, U4 pad_status) atom_dbg_skip MipsAtomComp_Proc_(ac_pad_set_status, ab, { +FI_ Slice_MipsCode ac_pad_set_status(AtomBuilder_R ab, U4 r_tmp, U1 r_state, U4 pad_status) atom_dbg_skip MipsAtomComp_Proc_(ab, { add_ui( r_tmp, R_0, pad_status), store_word(r_tmp, r_state, O_(PadState,status)), }) @@ -30,7 +31,7 @@ FI_ Slice_MipsCode ac_pad_set_status(AtomBuilder_R ab, U4 r_tmp, U1 r_state, U4 /* Invert r_buttons (active-low → active-high) and store to PadState.buttons. * r_buttons must already be loaded (the caller is responsible for filling the load-delay slot of * the preceding load_half_u with an instruction that doesn't read r_buttons). */ -FI_ Slice_MipsCode ac_pad_store_inverted_buttons(AtomBuilder_R ab, U1 r_buttons, U1 r_pad_state) atom_dbg_skip MipsAtomComp_Proc_(ac_pad_store_inverted_buttons, ab, { +FI_ Slice_MipsCode ac_pad_store_inverted_buttons(AtomBuilder_R ab, U1 r_buttons, U1 r_pad_state) atom_dbg_skip MipsAtomComp_Proc_(ab, { nor_u( r_buttons, r_buttons, R_0), store_half( r_buttons, r_pad_state, O_(PadState,buttons)), }) diff --git a/code/hello_camera/hello_camera.atom.c b/code/hello_camera/hello_camera.atom.c index aca34aa..7eae002 100644 --- a/code/hello_camera/hello_camera.atom.c +++ b/code/hello_camera/hello_camera.atom.c @@ -26,7 +26,7 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(hello_joypad_atom_c); #pragma region MACs (Mips Atom components) FI_ Slice_MipsCode ac_put_disp_env(AtomBuilder_R ab, U4 reg_transfer, U4 reg_base, U2 port) -MipsAtomComp_Proc_(ac_put_disp_env, ab, { +MipsAtomComp_Proc_(ab, { // Emits 5 GP0 commands for buffer 0 (display_area = (0,0,320,240)). // Sequence per libpsyx PutDispEnv: DrawArea TL → DrawArea BR → Mask → DrawArea TL → DrawArea BR mac_gcmd_push(gp0_word_draw_area_top_left_origin, reg_transfer, reg_base, port), @@ -37,7 +37,7 @@ MipsAtomComp_Proc_(ac_put_disp_env, ab, { }) I_ Slice_MipsCode ac_put_draw_env(AtomBuilder_R ab, U4 reg_transfer, U4 reg_base, U2 port) -MipsAtomComp_Proc_(ac_put_draw_env, ab, { +MipsAtomComp_Proc_(ab, { /* * ORIGIN: each code word corresponds to the EXACT value libpsyx's PutDrawEnv function would compute for the same DrawEnv settings. * References: @@ -151,7 +151,7 @@ internal MipsAtom* resolve_look_at__input_and_sub_proc(AtomArena_R aa, U4 r_scratch , U4 r_target_ptr,U4 r_eye_ptr, U4 r_up_in_ptr , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2, U4 r_tmp3 -) MipsAtom_Proc_(resolve_look_at__input_and_sub, aa, { +) MipsAtom_Proc_(aa, { load_word(r_target_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,target)), load_word(r_eye_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)), load_word(r_up_in_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)), @@ -182,7 +182,7 @@ internal MipsAtom* resolve_look_at__cross_uz_up_in_to_right_proc(AtomArena_R aa, , 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 = &right (out ptr), r_g = &uz, r_h = &up_in */ -) MipsAtom_Proc_(resolve_look_at__cross_uz_up_in_to_right, aa, { +) MipsAtom_Proc_(aa, { /* FIX: build packed RT22+RT33 with proper sign extension. */ add_si(r_g, r_scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */ add_si(r_h, r_scratch, O_(ResolveLookAtScratch,up_in)), /* r_h = &up_in */ @@ -266,7 +266,7 @@ internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa, U4 r_ , 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 */ -) MipsAtom_Proc_(resolve_look_at__cross_uz_ux_to_up, aa, { +) 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 */ @@ -363,7 +363,7 @@ internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa , U4 r_scratch , U4 r_pux, U4 r_puy, U4 r_puz , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2 -) MipsAtom_Proc_(resolve_look_at__populate, aa, { +) MipsAtom_Proc_(aa, { /* Pop look_at* (the matrix output) — advance R_TapePtr by 4 bytes. */ load_word(r_look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)), add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)), @@ -426,7 +426,7 @@ internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa , U4 r_peye , U4 r_look_at , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2 -) MipsAtom_Proc_(resolve_look_at__matrix_vector, aa, { +) MipsAtom_Proc_(aa, { /* === EXACT C11 ApplyMatrixLV replication === * The C11 does: * 1. ctc2 RT matrix (5 ctc2s to C2[0..4]) @@ -517,7 +517,7 @@ I_ MipsAtom* resolve_look_at__trans_matrix_proc(AtomArena_R aa , U4 r_tmp0 , U4 r_tmp1 , U4 r_tmp2 -) MipsAtom_Proc_(resolve_look_at__trans_matrix, 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)), diff --git a/code/hello_joypad/hello_joypad.atom.c b/code/hello_joypad/hello_joypad.atom.c index 0518ba1..528ab18 100644 --- a/code/hello_joypad/hello_joypad.atom.c +++ b/code/hello_joypad/hello_joypad.atom.c @@ -25,7 +25,7 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(hello_joypad_atom_c); #pragma region MACs (Mips Atom components) FI_ Slice_MipsCode ac_put_disp_env(MipsAtomBuilder_R ab, U4 reg_transfer, U4 reg_base, U2 port) -MipsAtomComp_Proc_(ac_put_disp_env, ab, { +MipsAtomComp_Proc_(ab, { // Emits 5 GP0 commands for buffer 0 (display_area = (0,0,320,240)). // Sequence per libpsyx PutDispEnv: DrawArea TL → DrawArea BR → Mask → DrawArea TL → DrawArea BR mac_gcmd_push(gp0_word_draw_area_top_left_origin, reg_transfer, reg_base, port), @@ -36,7 +36,7 @@ MipsAtomComp_Proc_(ac_put_disp_env, ab, { }) FI_ Slice_MipsCode ac_put_draw_env(MipsAtomBuilder_R ab, U4 reg_transfer, U4 reg_base, U2 port) -MipsAtomComp_Proc_(ac_put_draw_env, ab, { +MipsAtomComp_Proc_(ab, { /* * ORIGIN: each code word corresponds to the EXACT value libpsyx's PutDrawEnv function would compute for the same DrawEnv settings. * References: diff --git a/scripts/duffle.lua b/scripts/duffle.lua index eed6a3d..47cea62 100644 --- a/scripts/duffle.lua +++ b/scripts/duffle.lua @@ -2681,4 +2681,151 @@ function M.project_emission(body_text, component_index, word_counts, components) }) end -return M +------------------------------------------------------------------------------- +-- find_function_decl_for — backward walk for MipsAtomComp_Proc_ name extraction. +-- +-- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name +-- is derived from the preceding `FI_ Slice_MipsCode ac_X(args)` function +-- declaration. This function walks backward from `before_pos` to find it. +-- +-- Returns (raw_name, args_inner) or (nil, nil). +-- raw_name — e.g. "ac_load_word_imm" +-- args_inner — e.g. "AtomBuilder_R ab, Reg dst, U4 imm" +-- +-- The walk finds the LAST "Slice_MipsCode" before before_pos, then skips +-- whitespace + qualifiers (FI_, atom_dbg_skip, comments) until it finds an +-- ident followed by "(". That ident is the function name; the parens contents +-- are the args. +------------------------------------------------------------------------------- +function M.find_function_decl_for(source, before_pos, slice_mips_code_len) + local search_pos = 1 + local last_match = nil + while true do + local found = source:find("Slice_MipsCode", search_pos, true) + if not found or found >= before_pos then break end + last_match = found + search_pos = found + slice_mips_code_len + end + if not last_match then return nil, nil end + + local pos = last_match + slice_mips_code_len + while pos < before_pos do + -- skip whitespace + while pos <= #source do + local c = source:sub(pos, pos) + if c == " " or c == "\t" or c == "\n" or c == "\r" then + pos = pos + 1 + else + break + end + end + if pos > #source then break end + -- skip line comments + if source:sub(pos, pos + 1) == "//" then + while pos <= #source and source:sub(pos, pos) ~= "\n" do pos = pos + 1 end + pos = pos + 1 + goto continue + end + -- skip block comments + if source:sub(pos, pos + 1) == "/*" then + local close = source:find("*/", pos + 2, true) + if not close then break end + pos = close + 2 + goto continue + end + -- try to read an ident + local ident, ident_end = M.read_ident(source, pos) + if not ident then break end + -- check if the next non-ws char after ident is "(" + local next_pos = M.skip_ws_and_cmt(source, ident_end) + if source:sub(next_pos, next_pos) == "(" then + local inner = M.read_parens(source, next_pos) + if inner then + return ident, inner + end + end + -- ident not followed by "(" — it's a qualifier (FI_, atom_dbg_skip, etc); skip it + pos = ident_end + ::continue:: + end + return nil, nil +end + +------------------------------------------------------------------------------- +-- find_atom_proc_decl_for — backward walk for MipsAtom_Proc_ name extraction. +-- +-- After the `sym` arg was dropped from MipsAtom_Proc_, the atom name is +-- derived from the preceding `MipsAtom* X_proc(args)` function declaration. +-- This function walks backward from `before_pos` to find it. +-- +-- Returns (raw_name, args_inner) or (nil, nil). +-- raw_name — e.g. "normalize_v3s4" (the _proc suffix is stripped) +-- args_inner — e.g. "AtomArena_R aa, U4 r_scratch, ..." +-- +-- The walk finds the LAST "MipsAtom*" before before_pos, then skips +-- whitespace + qualifiers (internal, I_, FI_, comments) until it finds an +-- ident followed by "(". That ident is the function name (with _proc suffix); +-- the suffix is stripped to get raw_name. The parens contents are the args. +------------------------------------------------------------------------------- +function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len) + local search_pos = 1 + local last_match = nil + while true do + -- plain=true: "*" is literal, no escaping needed + local found = source:find("MipsAtom*", search_pos, true) + if not found or found >= before_pos then break end + last_match = found + search_pos = found + mips_atom_ptr_len + end + if not last_match then return nil, nil end + + local pos = last_match + mips_atom_ptr_len + while pos < before_pos do + -- skip whitespace + while pos <= #source do + local c = source:sub(pos, pos) + if c == " " or c == "\t" or c == "\n" or c == "\r" then + pos = pos + 1 + else + break + end + end + if pos > #source then break end + -- skip line comments + if source:sub(pos, pos + 1) == "//" then + while pos <= #source and source:sub(pos, pos) ~= "\n" do pos = pos + 1 end + pos = pos + 1 + goto continue + end + -- skip block comments + if source:sub(pos, pos + 1) == "/*" then + local close = source:find("*/", pos + 2, true) + if not close then break end + pos = close + 2 + goto continue + end + -- try to read an ident + local ident, ident_end = M.read_ident(source, pos) + if not ident then break end + -- check if the next non-ws char after ident is "(" + local next_pos = M.skip_ws_and_cmt(source, ident_end) + if source:sub(next_pos, next_pos) == "(" then + local inner = M.read_parens(source, next_pos) + if inner then + -- strip the _proc suffix to get the atom name + local proc_suffix = "_proc" + if #ident > #proc_suffix and ident:sub(-#proc_suffix) == proc_suffix then + return ident:sub(1, #ident - #proc_suffix), inner + end + -- no _proc suffix — return as-is + return ident, inner + end + end + -- ident not followed by "(" — it's a qualifier; skip it + pos = ident_end + ::continue:: + end + return nil, nil +end + + return M diff --git a/scripts/passes/components.lua b/scripts/passes/components.lua index da25de2..369feb6 100644 --- a/scripts/passes/components.lua +++ b/scripts/passes/components.lua @@ -96,48 +96,21 @@ local M = {} -- so this file reads it forward rather than re-walking the source. -- ════════════════════════════════════════════════════════════════════════════ ---- Find the args of the function declaration that immediately precedes a `MipsAtomComp_Proc_` invocation of the given name. +--- Find the args of the function declaration that immediately precedes a `MipsAtomComp_Proc_` invocation. --- Returns the args string (e.g., `"U4 off, U4 code, U1 r, U1 g, U1 b"`) or nil if no function declaration is found. --- ---- Convention: function form is ---- `FI_ Slice_MipsCode ac_X(args) MipsAtomComp_Proc_(ac_X, { body })` ---- We find the LAST occurrence of `"ac_X("` before `before_pos` and extract the args from inside the parens. ---- We then verify the preceding context ends with `Slice_MipsCode` ---- (the function-decl keyword with possible qualifiers between). +--- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name +--- and the args both come from the preceding `FI_ Slice_MipsCode ac_X(args)` +--- declaration. The shared `duffle.find_function_decl_for` helper does the +--- backward walk; this function returns just the args. --- --- @param source string ---- @param name string +--- @param name string (retained for signature stability; unused — the walk derives the name) --- @param before_pos integer --- @return string|nil local function find_function_args_for(source, name, before_pos) - -- Find the LAST occurrence of `name + "("` in `source[1..before_pos]`. - local name_open = name .. "(" - local last_idx = nil - local scan_pos = 1 - while true do - -- Pass `before_pos + 1` so string.find only returns positions < before_pos + 1 - -- (string.find's 4th arg `plain` is true; we use the 3rd arg `init` for the upper bound). - local found = source:find(name_open, scan_pos, true) - if not found or found >= before_pos then break end - last_idx = found - scan_pos = found + #name_open - end - if not last_idx then return nil end - - -- Verify the preceding context ends with "MipsAtom" (with possible qualifiers between). - local before = source:sub(1, last_idx - 1) - local trimmed = duffle.trim(before) - if trimmed:sub(-#MIPS_ATOM) ~= MIPS_ATOM then - -- Preceding context is not a function declaration. - return nil - end - - local open_paren = last_idx + #name -- position of "(" - -- scan: MipsAtom ac_X( - local inner = duffle.read_parens(source, open_paren) - -- scan: MipsAtom ac_X() - if not inner then return nil end - return inner + local _, args_inner = duffle.find_function_decl_for(source, before_pos, #MIPS_ATOM) + return args_inner end -- ════════════════════════════════════════════════════════════════════════════ diff --git a/scripts/passes/scan_source.lua b/scripts/passes/scan_source.lua index d3f4784..b034ed5 100644 --- a/scripts/passes/scan_source.lua +++ b/scripts/passes/scan_source.lua @@ -137,6 +137,16 @@ local QUALIFIER_KEYWORDS = { local AC_PREFIX = "ac_" local AC_PREFIX_LEN = 3 +-- The function-decl keyword that precedes a MipsAtomComp_Proc_ call. +-- Used by the backward walk in duffle.find_function_decl_for. +local SLICE_MIPS_CODE = "Slice_MipsCode" +local SLICE_MIPS_CODE_LEN = #SLICE_MIPS_CODE + +-- The return type that precedes a MipsAtom_Proc_ function declaration. +-- Used by the backward walk in duffle.find_atom_proc_decl_for. +local MIPS_ATOM_PTR = "MipsAtom*" +local MIPS_ATOM_PTR_LEN = #MIPS_ATOM_PTR + --- Strip the "ac_" prefix from a component name. --- Returns the input unchanged if it doesn't start with the prefix. --- @param raw_name string @@ -1357,7 +1367,11 @@ local function parse_mips_atom_comp_proc(source, pos, ident_end, line_of, out) local body, close_pos = duffle.read_braces(inner, last_brace_pos) if close_pos > #inner + 1 then return after_paren end - local raw_name = inner:match("^%s*([%w_]+)") or "?" + -- The component name is derived from the preceding function declaration + -- (`FI_ Slice_MipsCode ac_X(...)`), not from the first macro arg (which + -- is now `ab`). The backward walk finds the function decl before open_paren. + local raw_name = duffle.find_function_decl_for(source, open_paren, SLICE_MIPS_CODE_LEN) + if not raw_name then raw_name = "?" end local name = strip_ac_prefix(raw_name) -- Position of body[1] in source = open_paren + 1 (start of inner) + last_brace_pos + 1 (past '{'). local body_off = open_paren + 2 + last_brace_pos @@ -1398,9 +1412,12 @@ local function parse_mips_atom_proc(source, pos, ident_end, line_of, out) local body, close_pos = duffle.read_braces(inner, last_brace_pos) if close_pos > #inner + 1 then return after_paren end - -- The atom name is the FIRST ident of the args (matches MipsAtomComp_Proc_'s "first ident" rule). - -- MipsAtom_Proc_ has no `ac_` prefix; `strip_ac_prefix` is a no-op for unprefixed names. - local raw_name = inner:match("^%s*([%w_]+)") or "?" + -- The atom name is derived from the preceding function declaration + -- (`internal MipsAtom* X_proc(...)`), not from the first macro arg (which + -- is now `aa`). The backward walk finds the function decl before open_paren + -- and strips the `_proc` suffix. + local raw_name = duffle.find_atom_proc_decl_for(source, open_paren, MIPS_ATOM_PTR_LEN) + if not raw_name then raw_name = "?" end local name = strip_ac_prefix(raw_name) -- Position of body[1] in source = open_paren + 1 (start of inner) + last_brace_pos + 1 (past '{'). local body_off = open_paren + 2 + last_brace_pos