diff --git a/code/duffle/dsl.h b/code/duffle/dsl.h index 77fff3a..33881e5 100644 --- a/code/duffle/dsl.h +++ b/code/duffle/dsl.h @@ -87,7 +87,7 @@ #define PtrSet_(type) TypeR_(type); typedef TypeV_(type) #define TSet_(type) type; typedef PtrSet_(type) -#define array_len(a) (U8)(sizeof(a) / sizeof(typeof((a)[0]))) +#define array_len(a) (U4)(sizeof(a) / sizeof(typeof((a)[0]))) #define array_decl(type, ...) (type[]){__VA_ARGS__} #define Array_sym(type,len) A ## len ## _ ## type #define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len)) @@ -95,6 +95,7 @@ #define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b #define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol #define Proc_(symbol) symbol +#define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another. #define Struct_(symbol) struct symbol TSet_(symbol); struct symbol #define Union_(symbol) union symbol TSet_(symbol); union symbol @@ -140,7 +141,9 @@ typedef void Proc_(VoidFn) (void); #define tera(n) (C_(U4, n) << 40) #define null C_(U4, 0) #define nullptr C_(void*, 0) -#define O_(type,member) C_(U4,__builtin_offsetof(type,member)) +#define O_(type, field) (C_(U4, & C_(type*,0)->field)) + +#define OT_(field) O_(typeof_ptr(& field), filed)) #define S_(data) C_(U4, sizeof(data)) #define sop_1(op,a,b) C_(U1, s1_(a) op s1_(b)) @@ -171,8 +174,6 @@ def_signed_ops(le, <=) #define le_s(a,b) def_generic_sop(le, a,b) #undef def_generic_sop -#define o_(field) offset_of(typeof_ptr(& field), filed)) - #define alignas _Alignas #define alignof _Alignof #define byte_pad(amount, ...) B1 glue(_PAD_, __VA_ARGS__) [amount] diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index 2df9f2b..acae5a7 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -7,6 +7,7 @@ # include "memory.h" #endif + /* --------------------------------------------------------------------------- * TAPE DRIVE ABI & REGISTER ALIASES * --------------------------------------------------------------------------- @@ -29,20 +30,9 @@ enum { #define R_OtBase_Code R_T6_Code }; -/* The 'Yield' sequence for Tape Atoms. - * Loads the next pointer from the tape, advances the tape, and jumps. - * Cost: ~ 4 cycles */ -#define mips_yield() \ - load_word(R_T9, R_TapePtr, 0) \ - , add_ui_1( R_TapePtr, 4) \ - , jump_reg( R_T9) \ - , nop - /* The 'Exit' Atom */ MipsAtom_(tape_exit) { jump_reg(rret_addr), nop }; -typedef Slice_(U4); - /* Generalized Tape Engine Runner */ FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; asm volatile( asm_words( @@ -66,22 +56,33 @@ FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; a , clb_mem_drain ); } -typedef Struct_(TapeBuilder) { U4 ptr; U4 count; }; -FI_ void tb_init(TapeBuilder* tb, FArena* arena) { tb->ptr = arena->start; tb->count = 0; } +typedef Relative_(FArena) Struct_(TapeBuilder) { U4 ptr; U4 capacity; U4 used; }; +FI_ void tb_init(TapeBuilder* tb, FArena* arena) { tb->ptr = arena->start; tb->used = 0; } FI_ TapeBuilder tb_make( FArena* arena) { return (TapeBuilder){ arena->start, 0 }; } -FI_ void tb_emit(TapeBuilder* tb, MipsCode* atom) { u4_r(tb->ptr)[tb->count] = u4_(atom); ++ tb->count; } -FI_ void tb_data(TapeBuilder* tb, U4 data) { u4_r(tb->ptr)[tb->count] = u4_(data); ++ tb->count; } +#define tb_emit_(tb, atom) tb_emit(tb, tmpl(code,atom)) +FI_ void tb_emit(TapeBuilder* tb, MipsCode* atom) { u4_r(tb->ptr)[tb->used] = u4_(atom); ++ tb->used; } +FI_ void tb_data(TapeBuilder* tb, U4 data) { u4_r(tb->ptr)[tb->used] = u4_(data); ++ tb->used; } -FI_ Slice_U4 tb_end (TapeBuilder* tb) { tb_emit(tb,code_tape_exit); return (Slice_U4){ C_(U4*,tb->ptr), tb->count }; } -FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Slice_U4){ C_(U4*,tb.ptr), tb.count }; } +FI_ Slice_U4 tb_end (TapeBuilder* tb) { tb_emit(tb,code_tape_exit); return (Slice_U4){ C_(U4*,tb->ptr), tb->used }; } +FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Slice_U4){ C_(U4*,tb.ptr), tb.used }; } #define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,code_tape_exit)) +#pragma region Macro Mips Atom Components /* --------------------------------------------------------------------------- * MACRO ATOM Components (Reusable Assembly Components) * These do NOT yield. They are expanded inline inside Tape Atoms. * ---------------------------------------------------------------------------*/ +/* The 'Yield' sequence for Tape Atoms. + * Loads the next pointer from the tape, advances the tape, and jumps. + * Cost: ~ 4 cycles */ +#define mac_yield() \ + load_word(R_T9, R_TapePtr, 0) \ + , add_ui_1( R_TapePtr, 4) \ + , jump_reg( R_T9) \ + , nop + /* Loads 3 16-bit indices from the face array */ #define mac_load_tri_indices(rId_0, rId_1, rId_2) \ load_half_u(rId_0, R_FaceCur, 0) \ @@ -117,15 +118,39 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli , shift_lr( R_AT, R_AT, 8) \ , store_word(R_AT, R_T1, 0) /* OrderingTable[OTZ] = PrimCur */ -internal MipsAtom_(bind_workspace) { - /* Pop 4 arguments from the tape directly into the workspace registers */ - load_word(R_PrimCur, R_TapePtr, 0), - load_word(R_FaceCur, R_TapePtr, 4), - load_word(R_VertBase, R_TapePtr, 8), - load_word(R_OtBase, R_TapePtr, 12), - add_ui_1( R_TapePtr, 16), - mips_yield() -}; +#pragma endregion Macro Atom Components + +#pragma region Mips Atom Builder +// This allows for runtime procedural authoring of mips atoms. + +typedef Struct_(FMipsAtom512) { U4 data[512]; U4 used; }; + +typedef Slice_(MipsCode); typedef Slice_MipsCode MipsAtom; +// FArena Related +typedef Relative_(FArena) Struct_(MipsAtomBuilder) { U4 start; U4 capacity; U4 used; }; +// Whatever the builder is writting to should most likely coresspond +// to something that can fit within instruction cache? + +FI_ void atombuilder_unroll(MipsAtomBuilder_R ab, Slice_MipsCode_R code) { + assert(ab->capacity - ab->used - code->len); + mem_copy(ab->start, u4_(code->ptr), code->len); + mem_bump(ab->start, ab->capacity, & ab->used, code->len); +} +#define atombuilder_unroll_mac(ab, mac) + +// When done authoring, utilize this to cap-off the atom +FI_ void atombuilder_end(MipsAtomBuilder_R ab) { + LP_ MipsAtom_(yield) { mac_yield() }; + mem_copy(ab->start, u4_(code_yield), S_(code_yield)); + mem_bump(ab->start, ab->capacity, & ab->used, S_(code_yield)); +} + +#define mipsatom_from_builder(ab) (MipsAtom){ab.start, ab.used} + +#pragma endregion Mips Atom Builder + +#pragma region Baked Mips Atoms +// These atoms are resolved at compile time and are (usually) statically linked readonly data. internal MipsAtom_(sync_prim_cursor) { /* Pop the C-struct address and base address from the tape */ @@ -135,7 +160,7 @@ internal MipsAtom_(sync_prim_cursor) { /* Calculate byte offset and store directly back to RAM */ sub_u(R_T0, R_PrimCur, R_T0), store_word(R_T0, R_AT, 0), - mips_yield() + mac_yield() }; internal MipsAtom_(set_gte_world) { @@ -151,7 +176,26 @@ internal MipsAtom_(set_gte_world) { load_word(R_T0, R_T3, 20), load_word(R_T1, R_T3, 24), load_word(R_T2, R_T3, 28), gte_ct( R_T0, gte_cr_TRX), gte_ct( R_T1, gte_cr_TRY), gte_ct( R_T2, gte_cr_TRZ), - mips_yield() + mac_yield() +}; + + +// 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_PrimCur, R_TapePtr, O_(Binds_CubeTri,PrimCursor)), + load_word(R_FaceCur, 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)), + mac_yield() }; /* ============================================================================ @@ -283,7 +327,25 @@ internal MipsAtom_(cube_tri) { /* ── 12. Advance cursors & yield ─────────────────────────────────────── */ add_ui(R_PrimCur, R_PrimCur, 36), /* 9 words × 4 bytes */ add_ui(R_FaceCur, R_FaceCur, 8), /* 4 × S2 = 8 bytes */ - mips_yield() + 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_PrimCur, R_TapePtr, O_(Binds_FloorTri,PrimCursor)), + load_word(R_FaceCur, 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() }; internal MipsAtom_(floor_tri) { @@ -321,11 +383,11 @@ internal MipsAtom_(floor_tri) { add_ui(R_PrimCur, R_PrimCur, 20), /* Advance Prim Cursor (5 words) */ /* 9. Advance Input Cursor & Yield (Both branch targets land here) */ add_ui(R_FaceCur, R_FaceCur, 8), /* Advance Face Cursor (4 * S2 = 8 bytes) */ - mips_yield() + mac_yield() }; /* DIAGNOSTIC 1: Pure tape loop test */ -internal MipsAtom_(diag_yield) { mips_yield() }; +internal MipsAtom_(diag_yield) { mac_yield() }; /* DIAGNOSTIC 2: Pure memory test (No GTE). Draws a fixed cyan triangle. */ internal MipsAtom_(diag_color) { @@ -353,7 +415,7 @@ internal MipsAtom_(diag_color) { add_ui(R_T7, R_T7, 20), - mips_yield() + mac_yield() }; /* DIAGNOSTIC 3: Pure GTE test (No Memory Writes) */ @@ -384,5 +446,7 @@ internal MipsAtom_(diag_gte) { /* Advance Face Cursor and Yield */ add_ui(R_T4, R_T4, 8), - mips_yield() + mac_yield() }; + +#pragma endregion Baked Mips Atoms diff --git a/code/duffle/memory.h b/code/duffle/memory.h index 3a86802..2d2a72f 100644 --- a/code/duffle/memory.h +++ b/code/duffle/memory.h @@ -88,6 +88,8 @@ FI_ void slice_copy_(Slice dest, Slice src) { slice_copy_(slice_to_ut(dest), slice_to_ut(src)); \ } while(0) +typedef Slice_(U4); + #pragma endregion Slice #pragma region FArena diff --git a/code/gte_hello/hello_gte.c b/code/gte_hello/hello_gte.c index f6f0673..1bb8042 100644 --- a/code/gte_hello/hello_gte.c +++ b/code/gte_hello/hello_gte.c @@ -244,7 +244,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf) LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape)); TapeBuilder tb = tb_make(&tape_arena); tb_scope(& tb) { - tb_emit(& tb, code_bind_workspace); + tb_emit(& tb, code_rbind_cube_tri); tb_data(& tb, prim_cursor); tb_data(& tb, u4_(static_mem.cube.faces)); tb_data(& tb, u4_(static_mem.cube.verts)); @@ -334,12 +334,11 @@ void update(PrimitiveArena* pa, U4* ordering_buf) LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape)); TapeBuilder tb = tb_make(&tape_arena); tb_scope(& tb) { // Push "Protocol" to tape - tb_emit(& tb, code_bind_workspace); - tb_data(& tb, prim_cursor); - tb_data(& tb, u4_(static_mem.floor.faces)); - tb_data(& tb, u4_(static_mem.floor.verts)); - tb_data(& tb, u4_(ordering_buf)); - + tb_emit_(& tb, rbind_floor_tri); + tb_data(& tb, prim_cursor); + tb_data(& tb, u4_(static_mem.floor.faces)); + tb_data(& tb, u4_(static_mem.floor.verts)); + tb_data(& tb, u4_(ordering_buf)); tb_emit(& tb, code_set_gte_world); tb_data(& tb, u4_(& static_mem.tform_world));