mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-07 08:08:49 +00:00
WIP: still adjusting, deofuscating with annotation...
Problably will redesign the atom annotation DSL its too much curft rn, should be alot simpiler...
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* tape_atom_dsl.h
|
* atom_dsl.h
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
*
|
*
|
||||||
* TAPE ATOM DSL — annotation layer for tape atoms (lottes_tape.h).
|
* ATOM DSL — annotation layer for tape atoms (lottes_tape.h).
|
||||||
*
|
*
|
||||||
* This header turns `__attribute__((annotate(...)))` and `_Pragma(...)` into
|
* This header turns `__attribute__((annotate(...)))` and `_Pragma(...)` into
|
||||||
* a small named DSL that the metaprogram can validate against.
|
* a small named DSL that the metaprogram can validate against.
|
||||||
|
|||||||
+20
-189
@@ -44,14 +44,14 @@ MipsAtom_(tape_exit) { jump_reg(rret_addr), nop };
|
|||||||
/* Generalized Tape Engine Runner */
|
/* Generalized Tape Engine Runner */
|
||||||
FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; asm volatile(
|
FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; asm volatile(
|
||||||
asm_words(
|
asm_words(
|
||||||
add_ui( R_SP, R_SP, -8) /* Allocate stack space */
|
add_ui( R_SP, R_SP, -MipsStackAlignment) /* Allocate stack space */
|
||||||
, store_word(R_RA, R_SP, 0) /* Safely backup $ra to the stack */
|
, store_word(R_RA, R_SP, 0) /* Safely backup $ra to the stack */
|
||||||
, load_word( R_T9, R_TapePtr, 0) /* Bootstrap the first jump */
|
, load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
|
||||||
, add_ui_1( R_TapePtr, 4) /* Advance tape */
|
, add_ui_1( R_TapePtr, S_(MipsCode)) /* Advance tape */
|
||||||
, jump_nreg(R_T9) /* jalr $t9 */
|
, jump_nreg( R_AtomJmp) /* jalr $t9 */
|
||||||
, nop /* Branch delay slot */
|
, nop /* Branch delay slot */
|
||||||
, load_word(R_RA, R_SP, 0) /* Restore $ra from stack */
|
, load_word(R_RA, R_SP, 0) /* Restore $ra from stack */
|
||||||
, add_ui_1( R_SP, 8) /* Deallocate stack space */
|
, add_ui_1( R_SP, MipsStackAlignment) /* Deallocate stack space */
|
||||||
)
|
)
|
||||||
asm_rpins, r_use(tp)
|
asm_rpins, r_use(tp)
|
||||||
asm_clobber:
|
asm_clobber:
|
||||||
@@ -90,15 +90,15 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
|
|||||||
* Cost: ~ 4 cycles */
|
* Cost: ~ 4 cycles */
|
||||||
#define mac_yield() \
|
#define mac_yield() \
|
||||||
load_word(R_AtomJmp, R_TapePtr, 0) \
|
load_word(R_AtomJmp, R_TapePtr, 0) \
|
||||||
, add_ui_1( R_TapePtr, 4) \
|
, add_ui_1( R_TapePtr, S_(MipsCode)) \
|
||||||
, jump_reg( R_AtomJmp) \
|
, jump_reg( R_AtomJmp) \
|
||||||
, nop
|
, nop
|
||||||
|
|
||||||
/* Words: 3; Loads 3 S2 indices from the face array */
|
/* Words: 3; Loads 3 S2 indices from the face array */
|
||||||
#define mac_load_tri_indices(rId_0, rId_1, rId_2) \
|
#define mac_load_tri_indices(rId_0, rId_1, rId_2) \
|
||||||
load_half_u(rId_0, R_FaceCursor, 0) \
|
load_half_u(rId_0, R_FaceCursor, 0 * S_(S2)) \
|
||||||
, load_half_u(rId_1, R_FaceCursor, 2) \
|
, load_half_u(rId_1, R_FaceCursor, 1 * S_(S2)) \
|
||||||
, load_half_u(rId_2, R_FaceCursor, 4)
|
, load_half_u(rId_2, R_FaceCursor, 2 * S_(S2))
|
||||||
|
|
||||||
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE
|
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE
|
||||||
R_AT = rId_[#] << 3;
|
R_AT = rId_[#] << 3;
|
||||||
@@ -112,6 +112,7 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
|
|||||||
, shift_ll(R_AT, rId_1, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1) \
|
, shift_ll(R_AT, rId_1, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1) \
|
||||||
, shift_ll(R_AT, rId_2, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2)
|
, shift_ll(R_AT, rId_2, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2)
|
||||||
|
|
||||||
|
//TODO(Ed): Add more type annotation
|
||||||
/* Words: 11; Correctly inserts a primitive into the Ordering Table linked list */
|
/* Words: 11; Correctly inserts a primitive into the Ordering Table linked list */
|
||||||
#define mac_insert_ot_tag(r_otz, prim_length) \
|
#define mac_insert_ot_tag(r_otz, prim_length) \
|
||||||
shift_ll( R_T1, r_otz, 2) \
|
shift_ll( R_T1, r_otz, 2) \
|
||||||
@@ -176,6 +177,7 @@ enum {
|
|||||||
* 5. lw $ra, 4($sp); jr $ra ; restore & return
|
* 5. lw $ra, 4($sp); jr $ra ; restore & return
|
||||||
* 6. sp += 8
|
* 6. sp += 8
|
||||||
*/
|
*/
|
||||||
|
// TODO(Ed): Annotate magic offsets
|
||||||
internal MipsAtom_(mips_flush_icache) {
|
internal MipsAtom_(mips_flush_icache) {
|
||||||
add_ui(rstack_ptr, rstack_ptr, -8) /* sp -= 8 */
|
add_ui(rstack_ptr, rstack_ptr, -8) /* sp -= 8 */
|
||||||
, store_word(rret_addr, rstack_ptr, 4) /* sw $ra, 4($sp) */
|
, store_word(rret_addr, rstack_ptr, 4) /* sw $ra, 4($sp) */
|
||||||
@@ -189,11 +191,16 @@ internal MipsAtom_(mips_flush_icache) {
|
|||||||
, mac_yield()
|
, mac_yield()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef Struct_(Binds_SetGteWorld) {
|
||||||
|
U4 transform;
|
||||||
|
};
|
||||||
|
// TODO(Ed): Bugged, fix
|
||||||
internal MipsAtom_(set_gte_world) {
|
internal MipsAtom_(set_gte_world) {
|
||||||
/* Pop matrix address from tape into R_T3 ($11) */
|
/* Pop matrix address from tape into R_T3 ($11) */
|
||||||
load_word(R_T3, R_TapePtr, 0),
|
load_word(R_T3, R_TapePtr, O_(Binds_SetGteWorld,transform)),
|
||||||
add_ui_1( R_TapePtr, 4),
|
add_ui_1( R_TapePtr, S_(Binds_SetGteWorld)),
|
||||||
|
|
||||||
|
// TODO(Ed): Annotate magic offsets.
|
||||||
/* Load 3x3 Rotation + 3x1 Translation from R_T3 into GTE CONTROL Regs (ctc2) */
|
/* Load 3x3 Rotation + 3x1 Translation from R_T3 into GTE CONTROL Regs (ctc2) */
|
||||||
load_word(R_T0, R_T3, 0), load_word(R_T1, R_T3, 4),
|
load_word(R_T0, R_T3, 0), load_word(R_T1, R_T3, 4),
|
||||||
gte_ct( R_T0, gte_cr_RT11), gte_ct( R_T1, gte_cr_RT12),
|
gte_ct( R_T0, gte_cr_RT11), gte_ct( R_T1, gte_cr_RT12),
|
||||||
@@ -207,187 +214,10 @@ internal MipsAtom_(set_gte_world) {
|
|||||||
|
|
||||||
// TODO(Ed): I'm not sure yet if the bindings are redundant with the floortri atom yet.
|
// TODO(Ed): I'm not sure yet if the bindings are redundant with the floortri atom yet.
|
||||||
|
|
||||||
typedef Struct_(Binds_CubeTri) {
|
|
||||||
U4 PrimCursor;
|
|
||||||
U4 FaceCursor;
|
|
||||||
U4 VertBase;
|
|
||||||
U4 OtBase;
|
|
||||||
};
|
|
||||||
internal MipsAtom_(rbind_cube_tri) {
|
|
||||||
/* Pop 4 arguments from the tape directly into the workspace registers */
|
|
||||||
load_word(R_PrimCursor, R_TapePtr, O_(Binds_CubeTri,PrimCursor)),
|
|
||||||
load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,FaceCursor)),
|
|
||||||
load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,VertBase)),
|
|
||||||
load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,OtBase)),
|
|
||||||
add_ui_1( R_TapePtr, S_(Binds_CubeTri)),
|
|
||||||
// Note(Ed): This entire thing is argument shuffle?
|
|
||||||
// TODO(Ed): Eliminate
|
|
||||||
mac_yield()
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ============================================================================
|
|
||||||
* cube_tri — Draw one cube face (Gouraud-shaded quad) via the GTE tape pipeline
|
|
||||||
* ============================================================================
|
|
||||||
*
|
|
||||||
* Reads 4 indices from R_FaceCur (V4_S2 = 8 bytes), loads 4 vertices into
|
|
||||||
* the GTE, runs the PsyQ RotAverageNclip4 sequence, and renders a Poly_G4.
|
|
||||||
*
|
|
||||||
* PsyQ RotAverageNclip4 sequence:
|
|
||||||
* 1. Load V0=p0, V1=p1, V2=p2
|
|
||||||
* 2. RTPT → SXY0=p0, SXY1=p1, SXY2=p2, SZ1,SZ2,SZ3
|
|
||||||
* 3. NCLIP → MAC0 = cross(p0,p1,p2) ← BEFORE RTPS!
|
|
||||||
* 4. Store SXY0 (p0) to primitive buffer
|
|
||||||
* 5. Load V3 into V0
|
|
||||||
* 6. RTPS → SXY0=p3, SZ0
|
|
||||||
* 7. Store SXY0 (p3) to primitive buffer
|
|
||||||
* 8. AVSZ3 → OTZ from SZ1,SZ2,SZ3
|
|
||||||
*
|
|
||||||
* PRIMITIVE FORMAT (Poly_G4 = 9 words = 36 bytes)
|
|
||||||
* ------------------------------------------------
|
|
||||||
* Word 0 (offset 0): OT tag (set by mac_insert_ot_tag)
|
|
||||||
* Word 1 (offset 4): c0 + code = 0x38FF00FF (magenta, opcode 0x38)
|
|
||||||
* Word 2 (offset 8): p0 = SXY0 (stored BEFORE RTPS)
|
|
||||||
* Word 3 (offset 12): c1 + pad = 0x0000FFFF (yellow)
|
|
||||||
* Word 4 (offset 16): p1 = SXY1
|
|
||||||
* Word 5 (offset 20): c2 + pad = 0x00FFFF00 (cyan)
|
|
||||||
* Word 6 (offset 24): p2 = SXY2
|
|
||||||
* Word 7 (offset 28): c3 + pad = 0x0000FF00 (green)
|
|
||||||
* Word 8 (offset 32): p3 = SXY0 (stored AFTER RTPS)
|
|
||||||
*
|
|
||||||
* BRANCH OFFSETS
|
|
||||||
* ----------------------------------------------
|
|
||||||
* Outer branch (backface cull): branch_le_zero(R_T0, 49)
|
|
||||||
* → Skip 49 instructions from BD slot, land at add_ui(R_FaceCur,...)
|
|
||||||
* Inner branch (OTZ bounds): branch_equal(R_AT, R_0, 13)
|
|
||||||
* → Skip 13 instructions from BD slot, land at add_ui(R_FaceCur,...)
|
|
||||||
* ============================================================================ */
|
|
||||||
atom_region (cube_tri, REGION_PRIM_ARENA)
|
|
||||||
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))
|
|
||||||
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) */
|
|
||||||
|
|
||||||
/* ── 2. Load V0, V1, V2 into GTE ────────────────────────────────────── */
|
|
||||||
/* V0 = verts[face->x] */
|
|
||||||
shift_ll(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_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0),
|
|
||||||
|
|
||||||
/* V1 = verts[face->y] */
|
|
||||||
shift_ll(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_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1),
|
|
||||||
|
|
||||||
/* V2 = verts[face->z] */
|
|
||||||
shift_ll(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_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2),
|
|
||||||
|
|
||||||
/* ── 3. RTPT — transforms V0/V1/V2 → SXY0/SXY1/SXY2 + SZ1/SZ2/SZ3 ─── */
|
|
||||||
nop, nop, 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,
|
|
||||||
|
|
||||||
/* ── 5. Cull check: skip format/insert if MAC0 ≤ 0 (backface) ───────── */
|
|
||||||
gte_mf(R_T0, C2_MAC0),
|
|
||||||
nop,
|
|
||||||
branch_le_zero(R_T0, 49), /* Skip 49 if MAC0 ≤ 0 (backface) → cull */
|
|
||||||
nop, /* BD slot */
|
|
||||||
|
|
||||||
/* ── 6. Store p0,p1,p2 to primitive buffer (BEFORE RTPS overwrites) ─── */
|
|
||||||
store_word(R_0, R_PrimCursor, 0),
|
|
||||||
|
|
||||||
/* Word 1: c0 (BGR) + code = 0x38FF00FF (magenta, opcode 0x38) */
|
|
||||||
load_ui(R_AT, 0x38FF), or_i(R_AT, R_AT, 0x00FF),
|
|
||||||
store_word(R_AT, R_PrimCursor, 4),
|
|
||||||
|
|
||||||
/* Word 2: p0 = SXY0 (stored BEFORE RTPS overwrites it) */
|
|
||||||
gte_sw(C2_SXY0, R_PrimCursor, 8),
|
|
||||||
|
|
||||||
/* Word 3: c1 (BGR) + pad = 0x0000FFFF (yellow) */
|
|
||||||
load_ui(R_AT, 0x0000), or_i(R_AT, R_AT, 0xFFFF),
|
|
||||||
store_word(R_AT, R_PrimCursor, 12),
|
|
||||||
|
|
||||||
/* Word 4: p1 = SXY1 */
|
|
||||||
gte_sw(C2_SXY1, R_PrimCursor, 16),
|
|
||||||
|
|
||||||
/* Word 5: c2 (BGR) + pad = 0x00FFFF00 (cyan) */
|
|
||||||
load_ui(R_AT, 0x00FF), or_i(R_AT, R_AT, 0xFF00),
|
|
||||||
store_word(R_AT, R_PrimCursor, 20),
|
|
||||||
|
|
||||||
/* Word 6: p2 = SXY2 */
|
|
||||||
gte_sw(C2_SXY2, R_PrimCursor, 24),
|
|
||||||
|
|
||||||
/* Word 7: c3 (BGR) + pad = 0x0000FF00 (green) */
|
|
||||||
load_ui(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_ll(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_mt(R_V0, C2_VXY0), gte_mt(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_mf(R_T1, C2_OTZ),
|
|
||||||
|
|
||||||
/* ── 10. Bounds check OTZ < 2048 ─────────────────────────────────────── */
|
|
||||||
add_ui( R_AT, R_0, 2048),
|
|
||||||
slt_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, 0x0800), /* 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 */
|
|
||||||
mac_yield()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef Struct_(Binds_FloorTri) {
|
|
||||||
U4 PrimCursor;
|
|
||||||
U4 FaceCursor;
|
|
||||||
U4 VertBase;
|
|
||||||
U4 OtBase;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal MipsAtom_(rbind_floor_tri) {
|
|
||||||
/* Pop 4 arguments from the tape directly into the workspace registers */
|
|
||||||
load_word(R_PrimCursor, R_TapePtr, O_(Binds_FloorTri,PrimCursor)),
|
|
||||||
load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,FaceCursor)),
|
|
||||||
load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,VertBase)),
|
|
||||||
load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,OtBase)),
|
|
||||||
add_ui_1( R_TapePtr, S_(Binds_FloorTri)),
|
|
||||||
// Note(Ed): This entire thing is argument shuffle?
|
|
||||||
// TODO(Ed): Eliminate
|
|
||||||
mac_yield()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* DIAGNOSTIC 1: Pure tape loop test */
|
/* DIAGNOSTIC 1: Pure tape loop test */
|
||||||
internal MipsAtom_(diag_yield) { mac_yield() };
|
internal MipsAtom_(diag_yield) { mac_yield() };
|
||||||
|
|
||||||
|
// TODO(Ed): Reduce magic numbers/offsets
|
||||||
/* DIAGNOSTIC 2: Pure memory test (No GTE). Draws a fixed cyan triangle. */
|
/* DIAGNOSTIC 2: Pure memory test (No GTE). Draws a fixed cyan triangle. */
|
||||||
internal MipsAtom_(diag_color) {
|
internal MipsAtom_(diag_color) {
|
||||||
store_word(R_0, R_T7, 0),
|
store_word(R_0, R_T7, 0),
|
||||||
@@ -417,6 +247,7 @@ internal MipsAtom_(diag_color) {
|
|||||||
mac_yield()
|
mac_yield()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(Ed): Reduce magic numbers/offsets
|
||||||
/* DIAGNOSTIC 3: Pure GTE test (No Memory Writes) */
|
/* DIAGNOSTIC 3: Pure GTE test (No Memory Writes) */
|
||||||
internal MipsAtom_(diag_gte) {
|
internal MipsAtom_(diag_gte) {
|
||||||
/* Load 3 indices */
|
/* Load 3 indices */
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
# include "gcc_asm.h"
|
# include "gcc_asm.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MipsStackAlignment = 8,
|
||||||
|
};
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
* REGISTER INTEGER IDS (preprocessor-visible)
|
* REGISTER INTEGER IDS (preprocessor-visible)
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#pragma region hello_gte_tape
|
#pragma region hello_gte_tape
|
||||||
|
|
||||||
|
|
||||||
// --- atom: floor_tri (32 words) ---
|
// --- atom: floor_tri (51 words) ---
|
||||||
|
|
||||||
#define _atom_offset_culling_floor_tri_exit 17
|
#define _atom_offset_culling_floor_tri_exit 17
|
||||||
#define _atom_offset_bounds_chk_floor_tri_exit 3
|
#define _atom_offset_bounds_chk_floor_tri_exit 3
|
||||||
|
|||||||
+82
-74
@@ -96,6 +96,7 @@ typedef Struct_(Ent_Floor) {
|
|||||||
A2_V3_S2 faces;
|
A2_V3_S2 faces;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum { scratchpad_size = 1024, };
|
||||||
typedef Struct_(SMemory) {
|
typedef Struct_(SMemory) {
|
||||||
DoubleBuffer screen_buf;
|
DoubleBuffer screen_buf;
|
||||||
A2_OrderingTable_Buffer ordering_tbl;
|
A2_OrderingTable_Buffer ordering_tbl;
|
||||||
@@ -107,14 +108,19 @@ typedef Struct_(SMemory) {
|
|||||||
Ent_Cube cube;
|
Ent_Cube cube;
|
||||||
Ent_Floor floor;
|
Ent_Floor floor;
|
||||||
|
|
||||||
|
U4_V scratchpad; // d-cache
|
||||||
};
|
};
|
||||||
global SMemory static_mem;
|
global SMemory smem;
|
||||||
extern SMemory static_mem;
|
extern SMemory smem;
|
||||||
|
|
||||||
|
// TODO(Ed):
|
||||||
|
FI_ U4* spad_warm(MipsAtom atom) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
I_ B1* prim__alloc(U4 type_width, Str8 type_name) {
|
I_ B1* prim__alloc(U4 type_width, Str8 type_name) {
|
||||||
gknown PrimitiveArena* pa = & static_mem.primitives;
|
gknown PrimitiveArena* pa = & smem.primitives;
|
||||||
gknown B1* buf = (B1*) r_(static_mem.primitives.buf)[static_mem.active_buf_id];
|
gknown B1* buf = (B1*) r_(smem.primitives.buf)[smem.active_buf_id];
|
||||||
assert(pa->used + type_width < PrimitiveBuff_Len);
|
assert(pa->used + type_width < PrimitiveBuff_Len);
|
||||||
B1* next = buf + pa->used;
|
B1* next = buf + pa->used;
|
||||||
pa->used += type_width;
|
pa->used += type_width;
|
||||||
@@ -174,9 +180,9 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
orderingtbl_clear_reverse(ordering_buf, OrderingTbl_Len);
|
orderingtbl_clear_reverse(ordering_buf, OrderingTbl_Len);
|
||||||
|
|
||||||
// Update the position based on acceleration and velocity
|
// Update the position based on acceleration and velocity
|
||||||
gknown V3_S4_R pos = & static_mem.cube.pos;
|
gknown V3_S4_R pos = & smem.cube.pos;
|
||||||
gknown V3_S4_R vel = & static_mem.cube.vel;
|
gknown V3_S4_R vel = & smem.cube.vel;
|
||||||
gknown V3_S4_R acc = & static_mem.cube.accel;
|
gknown V3_S4_R acc = & smem.cube.accel;
|
||||||
add_v3s4(vel, acc[0]);
|
add_v3s4(vel, acc[0]);
|
||||||
add_v3s4_fp(pos, vel[0]);
|
add_v3s4_fp(pos, vel[0]);
|
||||||
// vel->x += acc->x;
|
// vel->x += acc->x;
|
||||||
@@ -186,7 +192,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
// pos->y += vel->y;
|
// pos->y += vel->y;
|
||||||
// pos->z += vel->z;
|
// pos->z += vel->z;
|
||||||
|
|
||||||
if (pos->y + 150 > static_mem.floor.pos.y) vel->y *= -1;
|
if (pos->y + 150 > smem.floor.pos.y) vel->y *= -1;
|
||||||
|
|
||||||
// Prep
|
// Prep
|
||||||
S4 nclip = 0;
|
S4 nclip = 0;
|
||||||
@@ -197,11 +203,11 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
// Draw Cube
|
// Draw Cube
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
m3s2_rotation (& static_mem.cube.rot, & static_mem.tform_world);
|
m3s2_rotation (& smem.cube.rot, & smem.tform_world);
|
||||||
m3s2_translation(& static_mem.tform_world, & static_mem.cube.pos);
|
m3s2_translation(& smem.tform_world, & smem.cube.pos);
|
||||||
m3s2_scale (& static_mem.tform_world, & static_mem.cube.scale);
|
m3s2_scale (& smem.tform_world, & smem.cube.scale);
|
||||||
gte_matrix_set_rotation (& static_mem.tform_world);
|
gte_matrix_set_rotation (& smem.tform_world);
|
||||||
gte_matrix_set_translation(& static_mem.tform_world);
|
gte_matrix_set_translation(& smem.tform_world);
|
||||||
for (U4 face_id = 0; face_id < Cube_num_faces; face_id += 1)
|
for (U4 face_id = 0; face_id < Cube_num_faces; face_id += 1)
|
||||||
{
|
{
|
||||||
Poly_G4* quad = prim_alloc(Poly_G4); set_poly_g4(quad);
|
Poly_G4* quad = prim_alloc(Poly_G4); set_poly_g4(quad);
|
||||||
@@ -210,11 +216,11 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
quad->c2 = rgb8( 0, 255, 255);
|
quad->c2 = rgb8( 0, 255, 255);
|
||||||
quad->c3 = rgb8( 0, 255, 0);
|
quad->c3 = rgb8( 0, 255, 0);
|
||||||
|
|
||||||
V4_S2* face = & static_mem.cube.faces[face_id];
|
V4_S2* face = & smem.cube.faces[face_id];
|
||||||
V3_S2* p0 = & static_mem.cube.verts[face->x];
|
V3_S2* p0 = & smem.cube.verts[face->x];
|
||||||
V3_S2* p1 = & static_mem.cube.verts[face->y];
|
V3_S2* p1 = & smem.cube.verts[face->y];
|
||||||
V3_S2* p2 = & static_mem.cube.verts[face->z];
|
V3_S2* p2 = & smem.cube.verts[face->z];
|
||||||
V3_S2* p3 = & static_mem.cube.verts[face->w];
|
V3_S2* p3 = & smem.cube.verts[face->w];
|
||||||
|
|
||||||
nclip = rtp_avg_nclip_a4_v3s2(
|
nclip = rtp_avg_nclip_a4_v3s2(
|
||||||
p0, p1, p2, p3,
|
p0, p1, p2, p3,
|
||||||
@@ -229,29 +235,29 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
orderingtbl_add_primitive(ordering_buf[orderingtbl_z], quad);
|
orderingtbl_add_primitive(ordering_buf[orderingtbl_z], quad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// static_mem.cube.rot.x += 6;
|
// smem.cube.rot.x += 6;
|
||||||
// static_mem.cube.rot.y += 8;
|
// smem.cube.rot.y += 8;
|
||||||
// static_mem.cube.rot.z += 12;
|
// smem.cube.rot.z += 12;
|
||||||
static_mem.cube.rot.y += 30;
|
smem.cube.rot.y += 30;
|
||||||
}
|
}
|
||||||
// Draw cube (tape method) - two triangles per face
|
// Draw cube (tape method) - two triangles per face
|
||||||
if (0)
|
if (0)
|
||||||
{
|
{
|
||||||
m3s2_rotation (& static_mem.cube.rot, & static_mem.tform_world);
|
m3s2_rotation (& smem.cube.rot, & smem.tform_world);
|
||||||
m3s2_translation(& static_mem.tform_world, & static_mem.cube.pos);
|
m3s2_translation(& smem.tform_world, & smem.cube.pos);
|
||||||
m3s2_scale (& static_mem.tform_world, & static_mem.cube.scale);
|
m3s2_scale (& smem.tform_world, & smem.cube.scale);
|
||||||
gte_matrix_set_rotation (& static_mem.tform_world);
|
gte_matrix_set_rotation (& smem.tform_world);
|
||||||
gte_matrix_set_translation(& static_mem.tform_world);
|
gte_matrix_set_translation(& smem.tform_world);
|
||||||
|
|
||||||
U4 prim_base = u4_(pa->buf[static_mem.active_buf_id]);
|
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
|
||||||
U4 prim_cursor = prim_base + pa->used;
|
U4 prim_cursor = prim_base + pa->used;
|
||||||
|
|
||||||
LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape));
|
LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape));
|
||||||
TapeBuilder tb = tb_make_old(&tape_arena); tb_scope(& tb) {
|
TapeBuilder tb = tb_make_old(&tape_arena); tb_scope(& tb) {
|
||||||
tb_emit(& tb, code_rbind_cube_tri);
|
tb_emit(& tb, code_rbind_cube_tri);
|
||||||
tb_data(& tb, prim_cursor);
|
tb_data(& tb, prim_cursor);
|
||||||
tb_data(& tb, u4_(static_mem.cube.faces));
|
tb_data(& tb, u4_(smem.cube.faces));
|
||||||
tb_data(& tb, u4_(static_mem.cube.verts));
|
tb_data(& tb, u4_(smem.cube.verts));
|
||||||
tb_data(& tb, u4_(ordering_buf));
|
tb_data(& tb, u4_(ordering_buf));
|
||||||
|
|
||||||
for (U4 i = 0; i < Cube_num_faces; i++) {
|
for (U4 i = 0; i < Cube_num_faces; i++) {
|
||||||
@@ -265,25 +271,25 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
}
|
}
|
||||||
tape_run(tb_slice(tb));
|
tape_run(tb_slice(tb));
|
||||||
|
|
||||||
static_mem.cube.rot.y += 30;
|
smem.cube.rot.y += 30;
|
||||||
}
|
}
|
||||||
// Draw Floor
|
// Draw Floor
|
||||||
if (0)
|
if (0)
|
||||||
{
|
{
|
||||||
m3s2_rotation (& static_mem.floor.rot, & static_mem.tform_world);
|
m3s2_rotation (& smem.floor.rot, & smem.tform_world);
|
||||||
m3s2_translation(& static_mem.tform_world, & static_mem.floor.pos);
|
m3s2_translation(& smem.tform_world, & smem.floor.pos);
|
||||||
m3s2_scale (& static_mem.tform_world, & static_mem.floor.scale);
|
m3s2_scale (& smem.tform_world, & smem.floor.scale);
|
||||||
gte_matrix_set_rotation (& static_mem.tform_world);
|
gte_matrix_set_rotation (& smem.tform_world);
|
||||||
gte_matrix_set_translation(& static_mem.tform_world);
|
gte_matrix_set_translation(& smem.tform_world);
|
||||||
for (U4 face_id = 0; face_id < Floor_num_faces; face_id += 1)
|
for (U4 face_id = 0; face_id < Floor_num_faces; face_id += 1)
|
||||||
{
|
{
|
||||||
Poly_F3* tri = prim_alloc(Poly_F3); set_poly_f3(tri);
|
Poly_F3* tri = prim_alloc(Poly_F3); set_poly_f3(tri);
|
||||||
tri->color = rgb8(255, 255, 255);
|
tri->color = rgb8(255, 255, 255);
|
||||||
|
|
||||||
V3_S2* face = & static_mem.floor.faces[face_id];
|
V3_S2* face = & smem.floor.faces[face_id];
|
||||||
register V3_S2* p0 rgcc(R_T4) = & static_mem.floor.verts[face->x];
|
register V3_S2* p0 rgcc(R_T4) = & smem.floor.verts[face->x];
|
||||||
register V3_S2* p1 rgcc(R_T5) = & static_mem.floor.verts[face->y];
|
register V3_S2* p1 rgcc(R_T5) = & smem.floor.verts[face->y];
|
||||||
register V3_S2* p2 rgcc(R_T6) = & static_mem.floor.verts[face->z];
|
register V3_S2* p2 rgcc(R_T6) = & smem.floor.verts[face->z];
|
||||||
|
|
||||||
// Three independent bases — full register discretion at the call site
|
// Three independent bases — full register discretion at the call site
|
||||||
gte_load_v0(p0, R_T4);
|
gte_load_v0(p0, R_T4);
|
||||||
@@ -320,48 +326,49 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static_mem.floor.rot.y += 5;
|
smem.floor.rot.y += 5;
|
||||||
}
|
}
|
||||||
// Draw floor tape method
|
// Draw floor tape method
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
m3s2_rotation (& static_mem.floor.rot, & static_mem.tform_world);
|
m3s2_rotation (& smem.floor.rot, & smem.tform_world);
|
||||||
m3s2_translation(& static_mem.tform_world, & static_mem.floor.pos);
|
m3s2_translation(& smem.tform_world, & smem.floor.pos);
|
||||||
m3s2_scale (& static_mem.tform_world, & static_mem.floor.scale);
|
m3s2_scale (& smem.tform_world, & smem.floor.scale);
|
||||||
gte_matrix_set_rotation (& static_mem.tform_world);
|
gte_matrix_set_rotation (& smem.tform_world);
|
||||||
gte_matrix_set_translation(& static_mem.tform_world);
|
gte_matrix_set_translation(& smem.tform_world);
|
||||||
|
|
||||||
U4 prim_base = u4_(pa->buf[static_mem.active_buf_id]);
|
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
|
||||||
U4 prim_cursor = prim_base + pa->used;
|
U4 prim_cursor = prim_base + pa->used;
|
||||||
|
|
||||||
// Prepare the tape.
|
// TODO(Ed): We should do a bounds check beforehand to confirm pa can hold all tris.
|
||||||
|
// The tape atoms in-flight should not need to care.
|
||||||
|
|
||||||
|
// Prepare the tape. (Push protocol to tape)
|
||||||
LP_ U4 mem_temp_tape[512];
|
LP_ U4 mem_temp_tape[512];
|
||||||
TapeBuilder tb = tb_make(slice_ut_arr(mem_temp_tape)); tb_scope(& tb) {
|
TapeBuilder tb = tb_make(slice_ut_arr(mem_temp_tape)); tb_scope(& tb) {
|
||||||
// Push "Protocol" to tape
|
// TODO(Ed): This is bugged.
|
||||||
|
// tb_emit(& tb, code_set_gte_world);
|
||||||
|
// tb_data(& tb, u4_(& smem.tform_world));
|
||||||
|
|
||||||
tb_emit(& tb, code_rbind_floor_tri);
|
tb_emit(& tb, code_rbind_floor_tri);
|
||||||
// TODO(Ed): Just use a single context struct ref
|
// TODO(Ed): Just use a single context struct ref
|
||||||
tb_data(& tb, prim_cursor);
|
tb_data(& tb, prim_cursor);
|
||||||
tb_data(& tb, u4_(static_mem.floor.faces));
|
tb_data(& tb, u4_(smem.floor.faces));
|
||||||
tb_data(& tb, u4_(static_mem.floor.verts));
|
tb_data(& tb, u4_(smem.floor.verts));
|
||||||
tb_data(& tb, u4_(ordering_buf));
|
tb_data(& tb, u4_(ordering_buf));
|
||||||
|
|
||||||
tb_emit(& tb, code_set_gte_world);
|
|
||||||
tb_data(& tb, u4_(& static_mem.tform_world));
|
|
||||||
|
|
||||||
for (U4 i = 0; i < Floor_num_faces; i++) {
|
for (U4 i = 0; i < Floor_num_faces; i++) {
|
||||||
tb_emit(& tb, code_floor_tri);
|
tb_emit(& tb, code_floor_tri);
|
||||||
}
|
}
|
||||||
// After code_floor_tri iterations complete, the primitive arena's used counter is wrong.
|
// After code_floor_tri iterations complete, the primitive arena's used counter needs updating.
|
||||||
tb_emit(& tb, code_sync_primitive_arena);
|
tb_emit(& tb, code_sync_primitive_arena);
|
||||||
tb_data(& tb, u4_(& pa->used));
|
tb_data(& tb, u4_(& pa->used));
|
||||||
tb_data(& tb, prim_base);
|
tb_data(& tb, prim_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire off the tape.
|
tape_run(tb_slice(tb));// Fire off the tape.
|
||||||
tape_run(tb_slice(tb));
|
|
||||||
|
|
||||||
// C-side state (pa->used) has already been updated by the tape!
|
// C-side state (pa->used) has already been updated by the tape!
|
||||||
static_mem.floor.rot.y += 5;
|
smem.floor.rot.y += 5;
|
||||||
}
|
}
|
||||||
// --- TAPE DIAGNOSTICS ---
|
// --- TAPE DIAGNOSTICS ---
|
||||||
if (0)
|
if (0)
|
||||||
@@ -381,40 +388,41 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
// tb_emit(& tb, code_diag_gte);
|
// tb_emit(& tb, code_diag_gte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
B1* prim_cursor = (B1*)r_(pa->buf)[static_mem.active_buf_id] + pa->used;
|
B1* prim_cursor = (B1*)r_(pa->buf)[smem.active_buf_id] + pa->used;
|
||||||
tape_run(tb_slice(tb));
|
tape_run(tb_slice(tb));
|
||||||
pa->used = (U4)prim_cursor - (U4)r_(pa->buf)[static_mem.active_buf_id];
|
pa->used = (U4)prim_cursor - (U4)r_(pa->buf)[smem.active_buf_id];
|
||||||
static_mem.floor.rot.y += 5;
|
smem.floor.rot.y += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
static_mem = (SMemory){0};
|
smem = (SMemory){0};
|
||||||
static_mem.primitives.used = 0;
|
smem.scratchpad = C_(U4_V, 0x1F800000);
|
||||||
ent_cube128_init(& static_mem.cube.verts, & static_mem.cube.faces); {
|
smem.primitives.used = 0;
|
||||||
Ent_Cube* cube = & static_mem.cube;
|
ent_cube128_init(& smem.cube.verts, & smem.cube.faces); {
|
||||||
|
Ent_Cube* cube = & smem.cube;
|
||||||
cube->rot = v3s2(0, 0, 0);
|
cube->rot = v3s2(0, 0, 0);
|
||||||
// cube->pos = v3s4(0, 0, 900);
|
// cube->pos = v3s4(0, 0, 900);
|
||||||
cube->scale = v3s4_fp_one();
|
cube->scale = v3s4_fp_one();
|
||||||
cube->accel = v3s4(0, 1, 0);
|
cube->accel = v3s4(0, 1, 0);
|
||||||
cube->pos = v3s4(0, -400, 1800);
|
cube->pos = v3s4(0, -400, 1800);
|
||||||
}
|
}
|
||||||
ent_floor_init(& static_mem.floor.verts, & static_mem.floor.faces); {
|
ent_floor_init(& smem.floor.verts, & smem.floor.faces); {
|
||||||
Ent_Floor* floor = & static_mem.floor;
|
Ent_Floor* floor = & smem.floor;
|
||||||
floor->rot = v3s2(0, 0, 0);
|
floor->rot = v3s2(0, 0, 0);
|
||||||
floor->pos = v3s4(0, 450, 1800);
|
floor->pos = v3s4(0, 450, 1800);
|
||||||
floor->scale = v3s4_fp_one();
|
floor->scale = v3s4_fp_one();
|
||||||
}
|
}
|
||||||
// gknown gp_screen_init();
|
// gknown gp_screen_init();
|
||||||
gp_screen_init_c11(& static_mem.screen_buf, & static_mem.active_buf_id);
|
gp_screen_init_c11(& smem.screen_buf, & smem.active_buf_id);
|
||||||
while (1) {
|
while (1) {
|
||||||
gknown S4* active_buf_id = & static_mem.active_buf_id;
|
gknown S4* active_buf_id = & smem.active_buf_id;
|
||||||
gknown U4* ordering_buf = r_(static_mem.ordering_tbl)[active_buf_id[0]];
|
gknown U4* ordering_buf = r_(smem.ordering_tbl)[active_buf_id[0]];
|
||||||
gknown PrimitiveArena* pa = & static_mem.primitives;
|
gknown PrimitiveArena* pa = & smem.primitives;
|
||||||
update(pa, ordering_buf);
|
update(pa, ordering_buf);
|
||||||
render();
|
render();
|
||||||
gp_display_frame(& static_mem.screen_buf, active_buf_id, ordering_buf, pa);
|
gp_display_frame(& smem.screen_buf, active_buf_id, ordering_buf, pa);
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+161
-26
@@ -23,6 +23,157 @@
|
|||||||
|
|
||||||
#pragma region Baked Atoms
|
#pragma region Baked Atoms
|
||||||
|
|
||||||
|
typedef Struct_(Binds_CubeTri) {
|
||||||
|
U4 PrimCursor;
|
||||||
|
U4 FaceCursor;
|
||||||
|
U4 VertBase;
|
||||||
|
U4 OtBase;
|
||||||
|
};
|
||||||
|
internal MipsAtom_(rbind_cube_tri) {
|
||||||
|
/* Pop 4 arguments from the tape directly into the workspace registers */
|
||||||
|
load_word(R_PrimCursor, R_TapePtr, O_(Binds_CubeTri,PrimCursor)),
|
||||||
|
load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,FaceCursor)),
|
||||||
|
load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,VertBase)),
|
||||||
|
load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,OtBase)),
|
||||||
|
add_ui_1( R_TapePtr, S_(Binds_CubeTri)),
|
||||||
|
// Note(Ed): This entire thing is argument shuffle?
|
||||||
|
// TODO(Ed): Eliminate
|
||||||
|
mac_yield()
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* cube_tri — Draw one cube face (Gouraud-shaded quad) via the GTE tape pipeline
|
||||||
|
* ============================================================================
|
||||||
|
*
|
||||||
|
* Reads 4 indices from R_FaceCur (V4_S2 = 8 bytes), loads 4 vertices into
|
||||||
|
* the GTE, runs the PsyQ RotAverageNclip4 sequence, and renders a Poly_G4.
|
||||||
|
*/
|
||||||
|
atom_region (cube_tri, REGION_PRIM_ARENA)
|
||||||
|
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))
|
||||||
|
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) */
|
||||||
|
|
||||||
|
/* ── 2. Load V0, V1, V2 into GTE ────────────────────────────────────── */
|
||||||
|
/* V0 = verts[face->x] */
|
||||||
|
shift_ll(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_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0),
|
||||||
|
|
||||||
|
/* V1 = verts[face->y] */
|
||||||
|
shift_ll(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_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1),
|
||||||
|
|
||||||
|
/* V2 = verts[face->z] */
|
||||||
|
shift_ll(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_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2),
|
||||||
|
|
||||||
|
/* ── 3. RTPT — transforms V0/V1/V2 → SXY0/SXY1/SXY2 + SZ1/SZ2/SZ3 ─── */
|
||||||
|
nop, nop, 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,
|
||||||
|
|
||||||
|
/* ── 5. Cull check: skip format/insert if MAC0 ≤ 0 (backface) ───────── */
|
||||||
|
gte_mf(R_T0, C2_MAC0),
|
||||||
|
nop,
|
||||||
|
branch_le_zero(R_T0, 49), /* Skip 49 if MAC0 ≤ 0 (backface) → cull */
|
||||||
|
nop, /* BD slot */
|
||||||
|
|
||||||
|
/* ── 6. Store p0,p1,p2 to primitive buffer (BEFORE RTPS overwrites) ─── */
|
||||||
|
store_word(R_0, R_PrimCursor, 0),
|
||||||
|
|
||||||
|
/* Word 1: c0 (BGR) + code = 0x38FF00FF (magenta, opcode 0x38) */
|
||||||
|
load_ui(R_AT, 0x38FF), or_i(R_AT, R_AT, 0x00FF),
|
||||||
|
store_word(R_AT, R_PrimCursor, 4),
|
||||||
|
|
||||||
|
/* Word 2: p0 = SXY0 (stored BEFORE RTPS overwrites it) */
|
||||||
|
gte_sw(C2_SXY0, R_PrimCursor, 8),
|
||||||
|
|
||||||
|
/* Word 3: c1 (BGR) + pad = 0x0000FFFF (yellow) */
|
||||||
|
load_ui(R_AT, 0x0000), or_i(R_AT, R_AT, 0xFFFF),
|
||||||
|
store_word(R_AT, R_PrimCursor, 12),
|
||||||
|
|
||||||
|
/* Word 4: p1 = SXY1 */
|
||||||
|
gte_sw(C2_SXY1, R_PrimCursor, 16),
|
||||||
|
|
||||||
|
/* Word 5: c2 (BGR) + pad = 0x00FFFF00 (cyan) */
|
||||||
|
load_ui(R_AT, 0x00FF), or_i(R_AT, R_AT, 0xFF00),
|
||||||
|
store_word(R_AT, R_PrimCursor, 20),
|
||||||
|
|
||||||
|
/* Word 6: p2 = SXY2 */
|
||||||
|
gte_sw(C2_SXY2, R_PrimCursor, 24),
|
||||||
|
|
||||||
|
/* Word 7: c3 (BGR) + pad = 0x0000FF00 (green) */
|
||||||
|
load_ui(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_ll(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_mt(R_V0, C2_VXY0), gte_mt(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_mf(R_T1, C2_OTZ),
|
||||||
|
|
||||||
|
/* ── 10. Bounds check OTZ < 2048 ─────────────────────────────────────── */
|
||||||
|
add_ui( R_AT, R_0, 2048),
|
||||||
|
slt_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, 0x0800), /* 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 */
|
||||||
|
mac_yield()
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Struct_(Binds_FloorTri) {
|
||||||
|
U4 PrimCursor;
|
||||||
|
U4 FaceCursor;
|
||||||
|
U4 VertBase;
|
||||||
|
U4 OtBase;
|
||||||
|
};
|
||||||
|
atom_region(rbind_floor_tri, REGION_PRIM_ARENA)
|
||||||
|
atom_group(rbind_floor_tri, GROUP_RENDER_FLOOR)
|
||||||
|
atom_cadence(rbind_floor_tri, CADENCE_FRAME)
|
||||||
|
atom_annot(rbind_floor_tri, phase_bind
|
||||||
|
, atom_reads()
|
||||||
|
, atom_writes(R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase))
|
||||||
|
internal
|
||||||
|
MipsAtom_(rbind_floor_tri) {
|
||||||
|
/* Pop 4 arguments from the tape directly into the workspace registers */
|
||||||
|
load_word(R_PrimCursor, R_TapePtr, O_(Binds_FloorTri,PrimCursor)),
|
||||||
|
load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,FaceCursor)),
|
||||||
|
load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,VertBase)),
|
||||||
|
load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,OtBase)),
|
||||||
|
add_ui_1( R_TapePtr, S_(Binds_FloorTri)),
|
||||||
|
mac_yield()
|
||||||
|
};
|
||||||
|
|
||||||
atom_region( floor_tri, REGION_PRIM_ARENA)
|
atom_region( floor_tri, REGION_PRIM_ARENA)
|
||||||
atom_group( floor_tri, GROUP_RENDER_FLOOR)
|
atom_group( floor_tri, GROUP_RENDER_FLOOR)
|
||||||
atom_cadence(floor_tri, CADENCE_FRAME)
|
atom_cadence(floor_tri, CADENCE_FRAME)
|
||||||
@@ -31,54 +182,38 @@
|
|||||||
atom_writes(R_PrimCursor, R_FaceCursor))
|
atom_writes(R_PrimCursor, R_FaceCursor))
|
||||||
internal
|
internal
|
||||||
MipsAtom_(floor_tri) {
|
MipsAtom_(floor_tri) {
|
||||||
// T0-T2 allocated
|
|
||||||
mac_load_tri_indices(R_T0, R_T1, R_T2),
|
mac_load_tri_indices(R_T0, R_T1, R_T2),
|
||||||
// load_half_u(R_T0, R_FaceCur, 0 * S_(S2))
|
|
||||||
// , load_half_u(R_T1, R_FaceCur, 1 * S_(S2))
|
|
||||||
// , load_half_u(R_T2, R_FaceCur, 2 * S_(S2))
|
|
||||||
// ,
|
|
||||||
mac_load_tri_verts( R_T0, R_T1, R_T2),
|
mac_load_tri_verts( R_T0, R_T1, R_T2),
|
||||||
// shift_ll(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_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0)
|
|
||||||
// , shift_ll(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_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1)
|
|
||||||
// , shift_ll(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_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2)
|
|
||||||
// ,
|
|
||||||
|
|
||||||
/* 3. Execute Math */
|
|
||||||
nop, nop, gte_cmdw_rotate_translate_perspective_triple,
|
nop, nop, gte_cmdw_rotate_translate_perspective_triple,
|
||||||
nop, nop, gte_cmdw_nclip,
|
nop, nop, gte_cmdw_nclip,
|
||||||
nop, nop,
|
nop, nop,
|
||||||
|
/* Culling (Branch forward if Backface) */
|
||||||
/* 4. Culling (Branch forward if Backface) */
|
|
||||||
gte_mf(R_T0, C2_MAC0),
|
gte_mf(R_T0, C2_MAC0),
|
||||||
nop, branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)),
|
nop, branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)),
|
||||||
nop,
|
nop,
|
||||||
|
/* Format Primitive */
|
||||||
/* 5. Format Primitive */
|
|
||||||
mac_format_f3_color(0x20FF, 0xFFFF),
|
mac_format_f3_color(0x20FF, 0xFFFF),
|
||||||
mac_gte_store_f3(),
|
mac_gte_store_f3(),
|
||||||
|
/* Calculate Depth */
|
||||||
/* 6. Calculate Depth */
|
|
||||||
nop, nop, gte_avg_sort_z3,
|
nop, nop, gte_avg_sort_z3,
|
||||||
nop, nop, gte_mf(R_T1, C2_OTZ),
|
nop, nop, gte_mf(R_T1, C2_OTZ),
|
||||||
|
/* Bounds Check OTZ < 2048 (Branch forward to skip insertion) */
|
||||||
/* 7. Bounds Check OTZ < 2048 (Branch forward to skip insertion) */
|
|
||||||
add_ui( R_AT, R_0, OrderingTbl_Len),
|
add_ui( R_AT, R_0, OrderingTbl_Len),
|
||||||
slt_u( R_AT, R_T1, R_AT),
|
slt_u( R_AT, R_T1, R_AT),
|
||||||
branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)),
|
branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)),
|
||||||
nop,
|
nop,
|
||||||
|
/* Insert into Ordering Table Linked List */
|
||||||
/* 8. Insert into Ordering Table Linked List */
|
|
||||||
mac_insert_ot_tag(R_T1, 0x0400),
|
mac_insert_ot_tag(R_T1, 0x0400),
|
||||||
add_ui_1(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
|
add_ui_1(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
|
||||||
// Note(Ed): No bounds checking, should be checked before atom runs.
|
// Note(Ed): No bounds checking, should be checked before atom runs.
|
||||||
|
|
||||||
/* 9. Advance Input Cursor & Yield (Both branch targets land here) */
|
/* Advance Input Cursor & Yield (Both branch targets land here) */
|
||||||
atom_label(floor_tri_exit)
|
atom_label(floor_tri_exit)
|
||||||
add_ui_1(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
add_ui_1(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
||||||
mac_yield()
|
mac_yield()
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Struct_(Binds_SyncPrimitiveArena) { U4 PrimtiveArena_Used; U4 PrimtiveBase; };
|
typedef Struct_(Binds_SyncPrimitiveArena) { U4 used; U4 cursor; };
|
||||||
atom_region( sync_primitive_arena, REGION_PRIM_ARENA)
|
atom_region( sync_primitive_arena, REGION_PRIM_ARENA)
|
||||||
atom_group( sync_primitive_arena, GROUP_RENDER_FLOOR)
|
atom_group( sync_primitive_arena, GROUP_RENDER_FLOOR)
|
||||||
atom_cadence(sync_primitive_arena, CADENCE_FRAME)
|
atom_cadence(sync_primitive_arena, CADENCE_FRAME)
|
||||||
@@ -86,11 +221,11 @@ typedef Struct_(Binds_SyncPrimitiveArena) { U4 PrimtiveArena_Used; U4 PrimtiveBa
|
|||||||
atom_reads( R_TapePtr, R_PrimCursor),
|
atom_reads( R_TapePtr, R_PrimCursor),
|
||||||
atom_writes(R_TapePtr))
|
atom_writes(R_TapePtr))
|
||||||
internal MipsAtom_(sync_primitive_arena) {
|
internal MipsAtom_(sync_primitive_arena) {
|
||||||
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,PrimtiveArena_Used)),
|
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,used)),
|
||||||
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,PrimtiveBase)),
|
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,cursor)),
|
||||||
add_ui_1( R_TapePtr, S_(Binds_SyncPrimitiveArena)),
|
add_ui_1( 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 - prim-base
|
sub_u( R_T0, R_PrimCursor, R_T0), // R_T0 = R_PrimCursor - binds.cursor
|
||||||
store_word(R_T0, R_AT, 0), // R_AT[0] = R_T0
|
store_word(R_T0, R_AT, 0), // R_AT[0] = R_T0
|
||||||
mac_yield()
|
mac_yield()
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user