diff --git a/code/duffle/atom_dsl.h b/code/duffle/atom_dsl.h index 564c424..4fc87ef 100644 --- a/code/duffle/atom_dsl.h +++ b/code/duffle/atom_dsl.h @@ -459,4 +459,9 @@ * ============================================================================*/ #define atom_offset(F, T) atom_offset_ ## F ## _ ## T -#define atom_label(name) /* anchor — see metaprogram documentation */ +/* atom_label is a pure annotation for the metaprogram's offset calculations. + * The macro expands to a C comment, so the C preprocessor strips it to + * whitespace — NO instruction word is emitted in the asm. The metaprogram + * still recognises the literal `atom_label(name)` token in source and + * records the marker at the current pos. */ +#define atom_label(name) /* atom_label anchor: name */ diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index d33006a..69a8e6e 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -119,21 +119,44 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli , shift_lright(R_AT, R_AT, S_(polytag_len_bits)) \ , store_word( R_AT, R_T1, O_(PolyTag,bf_addr_len)) /* OrderingTable[OTZ] = PrimCursor */ +/* Words: 3; Emits one (cmd|color) word to R_PrimCursor at the given + * byte offset. Internal helper used by the *_format_*_color macros. + * Args: off = U4 byte offset, code = GP0 cmd byte (0 for c1/c2/c3 of + * a Poly_G4), r/g/b = 8-bit RGB byte values. */ +#define mac_pack_color_word(off, code, r,g,b) \ + load_upper_i(R_AT, (code) << 8 | (b)) \ + , or_i_self( R_AT, ((g) << 8) | (r)) \ + , store_word( R_AT, R_PrimCursor, (off)) + /* Words: 3; Emits the F3 command+color word (cmd byte | BLUE | GREEN | RED) * Args: _r, _g, _b are 8-bit RGB byte values (not raw 16-bit fields). * Migrated from hello_gte_tape.c; takes RGB form per the Phase 3 * convention. */ -#define mac_format_f3_color(r,g,b) \ - load_upper_i(R_AT, gp0_cmd_poly_f3 << 8 | (b)) \ - , or_i_self( R_AT, ((g) << 8) | (r)) \ - , store_word( R_AT, R_PrimCursor, O_(Poly_F3,color)) +#define mac_format_f3_color(r,g,b) mac_pack_color_word(O_(Poly_F3,color), gp0_cmd_poly_f3, r,g,b) /* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3 */ #define mac_gte_store_f3() \ - gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_F3,p0)) \ + gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_F3,p0)) \ , gte_sw(C2_SXY1, R_PrimCursor, O_(Poly_F3,p1)) \ , gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_F3,p2)) +/* Words: 12; Emits the four (code|color) words of a Poly_G4. + * Args: rN,gN,bN are 8-bit RGB byte values for each of the 4 vertices. */ +#define mac_format_g4_color(r0,g0,b0, r1,g1,b1, r2,g2,b2, r3,g3,b3) \ + mac_pack_color_word(O_(Poly_G4,c0), gp0_cmd_poly_g4, r0,g0,b0) \ + , mac_pack_color_word(O_(Poly_G4,c1), 0, r1,g1,b1) \ + , mac_pack_color_word(O_(Poly_G4,c2), 0, r2,g2,b2) \ + , mac_pack_color_word(O_(Poly_G4,c3), 0, r3,g3,b3) + +/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices of the + * G4 triangle portion to p0/p1/p2. Call BEFORE the V3-RTPS, otherwise + * SXY0/SXY1/SXY2 get overwritten by the perspective transform. */ +#define mac_gte_store_g4_tri() \ + gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_G4,p0)) \ + , gte_sw(C2_SXY1, R_PrimCursor, O_(Poly_G4,p1)) \ + , gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_G4,p2)) + + #pragma endregion Macro Atom Components #pragma region Mips Atom Builder diff --git a/code/gte_hello/hello_gte.c b/code/gte_hello/hello_gte.c index 63b9efe..db7f848 100644 --- a/code/gte_hello/hello_gte.c +++ b/code/gte_hello/hello_gte.c @@ -154,6 +154,10 @@ void gp_screen_init_c11(DoubleBuffer* screen_buf, S4* active_buf_id) // Initialize and setup the GTE geometry offsets geom_init(); + // NOTE: geom_set_offset/geom_set_screen are kept as-is (the libgte versions + // are known to be broken in this PSYQ 4.7 build — see report 2026-07-09). + // The user's research wants the C-side non-tape reference to work as a + // known-good baseline for comparison against the tape. geom_set_offset(ScreenRes_CenterX, ScreenRes_CenterY); geom_set_screen(ScreenZ); @@ -201,12 +205,12 @@ void update(PrimitiveArena* pa, U4* ordering_buf) S4 flag; //???? // Draw Cube - if (1) + if (0) { m3s2_rotation (& smem.cube.rot, & smem.tform_world); m3s2_translation(& smem.tform_world, & smem.cube.pos); m3s2_scale (& smem.tform_world, & smem.cube.scale); - gte_matrix_set_rotation (& smem.tform_world); + // gte_matrix_set_rotation (& smem.tform_world); gte_matrix_set_translation(& smem.tform_world); for (U4 face_id = 0; face_id < Cube_num_faces; face_id += 1) { @@ -241,7 +245,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf) smem.cube.rot.y += 30; } // Draw cube (tape method) - two triangles per face - if (0) + if (1) { m3s2_rotation (& smem.cube.rot, & smem.tform_world); m3s2_translation(& smem.tform_world, & smem.cube.pos); @@ -384,7 +388,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf) // 2. code_diag_color -> Tests OT and Prim Arena memory // 3. code_diag_gte -> Tests Vertex arrays and GTE Math // tb_emit(& tb, code_diag_yield); - tb_emit(& tb, code_diag_color); + // tb_emit(& tb, code_diag_color); // tb_emit(& tb, code_diag_gte); } } diff --git a/code/gte_hello/hello_gte_tape.c b/code/gte_hello/hello_gte_tape.c index 384911e..59d205c 100644 --- a/code/gte_hello/hello_gte_tape.c +++ b/code/gte_hello/hello_gte_tape.c @@ -45,102 +45,69 @@ internal MipsAtom_(rbind_cube_tri) { atom_group (cube_tri, GROUP_RENDER_PRIMS) atom_cadence (cube_tri, CADENCE_FRAME) atom_annot(cube_tri, phase_work, - tape_regs(R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase), - tape_regs(R_PrimCursor, R_FaceCursor)) + atom_reads( R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase), + atom_writes(R_PrimCursor, R_FaceCursor)) internal MipsAtom_(cube_tri) { - /* ── 1. Load 4 face indices from R_FaceCur ──────────────────────────── */ - load_half_u(R_T0, R_FaceCursor, 0), /* T0 = face->x (vertex 0 index) */ - load_half_u(R_T1, R_FaceCursor, 2), /* T1 = face->y (vertex 1 index) */ - load_half_u(R_T2, R_FaceCursor, 4), /* T2 = face->z (vertex 2 index) */ - load_half_u(R_T3, R_FaceCursor, 6), /* T3 = face->w (vertex 3 index) */ + /* ── 1. Load 4 face indices from R_FaceCur (V4_S2 = 8 bytes) ───────── */ + load_half_u(R_T0, R_FaceCursor, 0 * 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_T3, R_FaceCursor, 3 * S_(S2)), - /* ── 2. Load V0, V1, V2 into GTE ────────────────────────────────────── */ - /* V0 = verts[face->x] */ - shift_lleft(R_AT, R_T0, 3), add_u(R_AT, R_AT, R_VertBase), - load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), - gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), + /* ── 2. Load V0, V1, V2 into GTE (parallel to mac_load_tri_verts) ── */ - /* V1 = verts[face->y] */ - shift_lleft(R_AT, R_T1, 3), add_u(R_AT, R_AT, R_VertBase), - load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), - gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1), - - /* V2 = verts[face->z] */ - shift_lleft(R_AT, R_T2, 3), add_u(R_AT, R_AT, R_VertBase), - load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), - gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2), + mac_load_tri_verts(R_T0, R_T1, R_T2), /* ── 3. RTPT — transforms V0/V1/V2 → SXY0/SXY1/SXY2 + SZ1/SZ2/SZ3 ─── */ - nop, nop, gte_cmdw_rtpt, + nop2, gte_cmdw_rtpt, /* ── 4. NCLIP — backface culling on SXY0/SXY1/SXY2 (p0,p1,p2) ──────── */ - /* MUST be done BEFORE RTPS overwrites SXY0 with p3! */ - nop, nop, gte_cmdw_nclip, - nop, nop, + /* MUST be done BEFORE V3-RTPS overwrites SXY0 with p3. */ + nop2, gte_cmdw_nclip, /* ── 5. Cull check: skip format/insert if MAC0 ≤ 0 (backface) ───────── */ - gte_mv_from_data_r(R_T0, C2_MAC0), - nop, - branch_le_zero(R_T0, 49), /* Skip 49 if MAC0 ≤ 0 (backface) → cull */ - nop, /* BD slot */ + nop2, gte_mv_from_data_r(R_T0, C2_MAC0), + nop, /* COP2 stall */ + branch_le_zero(R_T0, atom_offset(cull, cube_tri_exit)), + nop, /* BD slot */ - /* ── 6. Store p0,p1,p2 to primitive buffer (BEFORE RTPS overwrites) ─── */ - store_word(R_0, R_PrimCursor, 0), + /* ── 6. Format c0..c3 (color+code words) BEFORE V3-RTPS ─────────────── */ + store_word(R_0, R_PrimCursor, O_(Poly_G4, tag)), + mac_format_g4_color( + /* c0 magenta */ 0xFF, 0x00, 0xFF, + /* c1 yellow */ 0xFF, 0xFF, 0x00, + /* c2 cyan */ 0x00, 0xFF, 0xFF, + /* c3 green */ 0x00, 0xFF, 0x00), - /* Word 1: c0 (BGR) + code = 0x38FF00FF (magenta, opcode 0x38) */ - load_upper_i(R_AT, 0x38FF), or_i(R_AT, R_AT, 0x00FF), - store_word(R_AT, R_PrimCursor, 4), + /* ── 7. Store p0..p2 BEFORE V3-RTPS overwrites SXY0 ─────────────────── */ + mac_gte_store_g4_tri(), - /* Word 2: p0 = SXY0 (stored BEFORE RTPS overwrites it) */ - gte_sw(C2_SXY0, R_PrimCursor, 8), + /* ── 8. Load V3 = verts[face->w] into V0 ─────────────────────────────── */ + 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)), + gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), - /* Word 3: c1 (BGR) + pad = 0x0000FFFF (yellow) */ - load_upper_i(R_AT, 0x0000), or_i(R_AT, R_AT, 0xFFFF), - store_word(R_AT, R_PrimCursor, 12), + /* ── 9. RTPS — transforms V0 (now V3) → SXY0 (p3) + SZ3 ─────────────── */ + nop2, gte_cmdw_rtps, + mac_gte_store_g4_p3(), - /* Word 4: p1 = SXY1 */ - gte_sw(C2_SXY1, R_PrimCursor, 16), + /* ── 10. AVSZ4 — average Z from SZ0/SZ1/SZ2/SZ3 ─────────────────────── */ + nop2, gte_cmdw_avsz4, + nop2, gte_mv_from_data_r(R_T1, C2_OTZ), - /* Word 5: c2 (BGR) + pad = 0x00FFFF00 (cyan) */ - load_upper_i(R_AT, 0x00FF), or_i(R_AT, R_AT, 0xFF00), - store_word(R_AT, R_PrimCursor, 20), + /* ── 11. Bounds check OTZ < OrderingTbl_Len ─────────────────────────── */ + add_ui( R_AT, R_0, OrderingTbl_Len), + set_lt_u( R_AT, R_T1, R_AT), + branch_equal(R_AT, R_0, atom_offset(bounds_chk, cube_tri_exit)), nop, - /* Word 6: p2 = SXY2 */ - gte_sw(C2_SXY2, R_PrimCursor, 24), + /* ── 12. Insert into Ordering Table (length = 8 words for Poly_G4) ──── */ + mac_insert_ot_tag(R_T1, Poly_G4), - /* Word 7: c3 (BGR) + pad = 0x0000FF00 (green) */ - load_upper_i(R_AT, 0x0000), or_i(R_AT, R_AT, 0xFF00), - store_word(R_AT, R_PrimCursor, 28), - - /* ── 7. Load V3 = verts[face->w] into V0 ─────────────────────────────── */ - shift_lleft(R_AT, R_T3, 3), add_u(R_AT, R_AT, R_VertBase), - load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), - gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), - - /* ── 8. RTPS — transforms V0 (now V3) → SXY0 (p3) + SZ0 ─────────────── */ - nop, nop, gte_cmdw_rtps, - - /* Word 8: p3 = SXY0 (written AFTER RTPS with V3's screen coords) */ - gte_sw(C2_SXY0, R_PrimCursor, 32), - - /* ── 9. AVSZ4 — average Z from SZ0/SZ1/SZ2/SZ3 ────────────── */ - nop, nop, gte_cmdw_avsz4, - nop, nop, - gte_mv_from_data_r(R_T1, C2_OTZ), - - /* ── 10. Bounds check OTZ < 2048 ─────────────────────────────────────── */ - add_ui( R_AT, R_0, 2048), - set_lt_u( R_AT, R_T1, R_AT), - branch_equal(R_AT, R_0, 13), /* Skip 13 → land at add_ui(R_FaceCur,...) */ - nop, /* BD slot */ - - /* ── 11. Insert into Ordering Table (length = 8 for Poly_G4) ─────────── */ - mac_insert_ot_tag(R_T1, Poly_G4), /* 0x0800 = 8 << 8 = length 8 in tag */ - - /* ── 12. Advance cursors & yield ─────────────────────────────────────── */ - add_ui(R_PrimCursor, R_PrimCursor, 36), /* 9 words × 4 bytes */ - add_ui(R_FaceCursor, R_FaceCursor, 8), /* 4 × S2 = 8 bytes */ + /* ── 13. Advance cursors & yield (both branch targets land here) ────── */ +atom_label(cube_tri_exit) + add_ui_self(R_PrimCursor, S_(Poly_G4)), /* 9 words = Poly_G4 */ + add_ui_self(R_FaceCursor, S_(S2) * 4), /* 4 × S2 = 8 bytes */ mac_yield() }; @@ -179,11 +146,11 @@ MipsAtom_(floor_tri) { mac_load_tri_verts( R_T0, R_T1, R_T2), nop2, gte_cmdw_rotate_translate_perspective_triple, nop2, gte_cmdw_nclip, - nop2, + /* Culling (Branch forward if Backface) */ - gte_mv_from_data_r(R_T0, C2_MAC0), - nop, branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)), - nop, + nop2, gte_mv_from_data_r(R_T0, C2_MAC0), + nop, + branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)), nop, /* Format Primitive */ // mac_format_f3_color(0x20FF, 0xFFFF), // works mac_format_f3_color(0xFF, 0xFF, 0xFF), // RGB-form (R=FF, G=FF, B=FF = white) @@ -195,8 +162,7 @@ MipsAtom_(floor_tri) { /* Bounds Check OTZ < 2048 (Branch forward to skip insertion) */ add_ui( R_AT, R_0, OrderingTbl_Len), set_lt_u( R_AT, R_T1, R_AT), - branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)), - nop, + branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)), nop, /* Insert into Ordering Table Linked List */ mac_insert_ot_tag(R_T1, Poly_F3), add_ui_self(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */ diff --git a/code/gte_hello/tape_atom.metadata.h b/code/gte_hello/tape_atom.metadata.h index 3126e88..86ccba2 100644 --- a/code/gte_hello/tape_atom.metadata.h +++ b/code/gte_hello/tape_atom.metadata.h @@ -45,10 +45,16 @@ WORD_COUNT(gte_sw, 1) WORD_COUNT(gte_cmdw_rtpt, 1) WORD_COUNT(gte_cmdw_nclip, 1) WORD_COUNT(gte_avg_sort_z3, 1) +WORD_COUNT(sub_u, 1) +WORD_COUNT(nop2, 2) WORD_COUNT(mac_load_tri_indices, 3) WORD_COUNT(mac_load_tri_verts, 18) WORD_COUNT(mac_format_f3_color, 3) WORD_COUNT(mac_gte_store_f3, 3) +WORD_COUNT(mac_pack_color_word, 3) +WORD_COUNT(mac_format_g4_color, 12) +WORD_COUNT(mac_gte_store_g4_tri, 3) +WORD_COUNT(mac_gte_store_g4_p3, 1) WORD_COUNT(mac_insert_ot_tag, 11) WORD_COUNT(mac_yield, 4)