From 52888015deab3b205b4b273e53dea374b2877788 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 22 Aug 2026 20:06:14 -0400 Subject: [PATCH] reviewing --- .vscode/tape-atom-syntax/classifier.js | 4 ++-- .vscode/tape-atom-syntax/source-index.js | 2 +- code/duffle/dsl.atom.h | 2 +- code/duffle/dsl.h | 9 ++++---- code/duffle/gcc_asm.h | 8 ------- code/duffle/gen/macs.h | 22 +++++++++---------- code/duffle/gen/offsets.h | 2 +- code/duffle/gp.h | 17 +-------------- code/duffle/{gte.atom.c => gte.atom.h} | 23 +++++++++----------- code/duffle/gte.h | 27 +----------------------- code/duffle/memory.h | 7 +++--- code/duffle/mips.h | 9 ++------ code/duffle/pad.c | 13 ++---------- code/hello_camera/hello_camera.atom.c | 4 ++-- code/hello_camera/hello_camera.c | 2 +- 15 files changed, 43 insertions(+), 108 deletions(-) rename code/duffle/{gte.atom.c => gte.atom.h} (97%) diff --git a/.vscode/tape-atom-syntax/classifier.js b/.vscode/tape-atom-syntax/classifier.js index 4db0fef..89d8121 100644 --- a/.vscode/tape-atom-syntax/classifier.js +++ b/.vscode/tape-atom-syntax/classifier.js @@ -21,7 +21,7 @@ const TOKEN_TYPES = [ "tapeGprRegister", "tapeCop2Register", "tapeDuffleType", - "tapeAttribute", + "tapeAt__ibute", "keyword", "macro", ]; @@ -43,7 +43,7 @@ const DSL_KEYWORDS = new Set([ "Slice_", "TypeR_", "TypeV_", "align_", "internal", "local_persist", "global", "RO_", "LP_", "gknown", "expect_", "cexpr_", "asm", "asm_words", "asm_rpins", "asm_clobber", - "O_", "S_", "C_", "T_", "tmpl", "glue", "r_", "v_", "tr_", "tv_", + "O_", "S_", "C_", "T_", "tmpl", "glue", "r_", "v_", "rt_", "vt_", "rgcc", "r_use", "r_set", "r_mod", "r_imm", "r_mem", "u1_", "u2_", "u4_", "u8_", "s1_", "s2_", "s4_", "s8_", "u1_r", "u2_r", "u4_r", "u8_r", "u1_v", "u2_v", "u4_v", "u8_v", diff --git a/.vscode/tape-atom-syntax/source-index.js b/.vscode/tape-atom-syntax/source-index.js index 0e5cb07..28728f2 100644 --- a/.vscode/tape-atom-syntax/source-index.js +++ b/.vscode/tape-atom-syntax/source-index.js @@ -19,7 +19,7 @@ const BASE_ATTRIBUTES = [ "Slice_", "TypeR_", "TypeV_", "align_", "internal", "local_persist", "global", "RO_", "LP_", "gknown", "expect_", "cexpr_", "asm", "asm_words", "asm_rpins", "asm_clobber", - "O_", "S_", "C_", "T_", "tmpl", "glue", "r_", "v_", "tr_", "tv_", + "O_", "S_", "C_", "T_", "tmpl", "glue", "r_", "v_", "rt_", "vt_", "rgcc", "r_use", "r_set", "r_mod", "r_imm", "r_mem", "u1_", "u2_", "u4_", "u8_", "s1_", "s2_", "s4_", "s8_", "u1_r", "u2_r", "u4_r", "u8_r", "u1_v", "u2_v", "u4_v", "u8_v", diff --git a/code/duffle/dsl.atom.h b/code/duffle/dsl.atom.h index 0ffec4e..084fb60 100644 --- a/code/duffle/dsl.atom.h +++ b/code/duffle/dsl.atom.h @@ -44,7 +44,7 @@ * * Annotation rules * ---------------- - * 1. atom_info(...) is OPTIONAL. Atoms without atom_info are silently skipped by the metaprogram. + * 1. atom_info(...) is optional. Atoms without atom_info are silently skipped by the metaprogram. * 2. If present, atom_info takes up to three sub-calls, all order-independent within the arg list: * - atom_bind(Binds_X) * - atom_reads(...) diff --git a/code/duffle/dsl.h b/code/duffle/dsl.h index c11935c..a5e9551 100644 --- a/code/duffle/dsl.h +++ b/code/duffle/dsl.h @@ -29,7 +29,7 @@ #define asm __asm__ -#define A_(data) (& data) +#define A_(data) (& (data)) #define align_(value) __attribute__((aligned (value))) // for easy alignment #define align_(value) __attribute__((aligned (value))) // for easy alignment #define C_(type,data) ((type)(data)) // for enforced precedence @@ -45,7 +45,8 @@ #define R_ restrict #define V_ volatile -#pragma region Fictional //, used for intiution +#pragma region Fictional +//, used for intiution #define EUB_ restrict // Execute Unit Bound: Data is siloed in the ALU Register File. The Load/Store Unit is bypassed. (Route to Execution Unit. Keep in registers) #define ISO_ restrict // Isolated Provenance: Alternative to Exu_. Guarantees electrical memory isolation, @@ -83,8 +84,8 @@ #define r_(ptr) C_(T_(ptr[0])*R_, ptr) // Constrain pointer to restrict #define v_(ptr) C_(T_(ptr[0])V_*, ptr) // -#define tr_(type, ptr) C_(type *R_, ptr) -#define tv_(type, ptr) C_(type V_*, ptr) +#define rt_(type, ptr) C_(type *R_, ptr) +#define vt_(type, ptr) C_(type V_*, ptr) #define TypeR_(type) type *R_ type ## _R // type *restrict type_R #define TypeV_(type) type V_* type ## _V // type volatile* type_V diff --git a/code/duffle/gcc_asm.h b/code/duffle/gcc_asm.h index dc403b9..64160e2 100644 --- a/code/duffle/gcc_asm.h +++ b/code/duffle/gcc_asm.h @@ -79,14 +79,6 @@ * Why bundle the `__asm__()` wrapper? * - The integer R_T4 (= 12, via R_T4_Code) already indicates the register. * - The string "$12" is derived from it via reg_str, so they cannot drift apart. - * - Spelling `__asm__(reg_str(R_T4_Code))` at every call site is noise. - * - * tmpl defined in dsl.h (token-paste glue). - * rgcc define here (gcc_asm.h) because the `__asm__` keyword is GCC-specific. - * Anyone porting to a different compiler's asm dialect overrides rgcc, - * and the integer→string derivation in rlit can be retargeted in one place. - * - * For clobber lists and asm-template strings, use the bare `rlit(R_T4_Code)`. * ------------------------------------------------------------------------ */ #define rgcc(n) __asm__(rlit(n)) diff --git a/code/duffle/gen/macs.h b/code/duffle/gen/macs.h index 34daca9..65b58cf 100644 --- a/code/duffle/gen/macs.h +++ b/code/duffle/gen/macs.h @@ -19,7 +19,7 @@ // source: C:\projects\Pikuma\ps1\code\duffle\pad.c // source: C:\projects\Pikuma\ps1\code\duffle\math.atom.h // source: C:\projects\Pikuma\ps1\code\duffle\mips.atom.c -// source: C:\projects\Pikuma\ps1\code\duffle\gte.atom.c +// source: C:\projects\Pikuma\ps1\code\duffle\gte.atom.h // source: C:\projects\Pikuma\ps1\code\duffle\gp.atom.c // source: C:\projects\Pikuma\ps1\code\duffle\pad.atom.c // source: C:\projects\Pikuma\ps1\code\duffle\psyq.atom.c @@ -270,10 +270,10 @@ WORD_COUNT(mac_gte_store_g4_p3, 1) WORD_COUNT(mac_gte_sqr_v3, 8) /* atom_dbg_skip */ -#define mac_gte_sqr_v3s4(r_sx, r_sy, r_sz, delay_slot) \ - gte_mv_to_data_r(r_sx, C2_IR1) \ -, gte_mv_to_data_r(r_sy, C2_IR2) \ -, gte_mv_to_data_r(r_sz, C2_IR3) \ +#define mac_gte_sqr_v3s4(sx, sy, sz, delay_slot) \ + gte_mv_to_data_r(sx, C2_IR1) \ +, gte_mv_to_data_r(sy, C2_IR2) \ +, gte_mv_to_data_r(sz, C2_IR3) \ , delay_slot \ , gte_cmdw_sqr WORD_COUNT(mac_gte_sqr_v3s4, 5) @@ -304,12 +304,12 @@ WORD_COUNT(mac_gte_gpf_scale, 13) WORD_COUNT(mac_trans_mt3s3s4, 6) /* atom_dbg_skip */ -#define mac_lzcr_round_even_half_shift(r_shift, r_mag_sq, r_mag_sq_copy) \ - and_i(r_shift, r_shift, gte_lzcr_even_mask) \ -, or_u(r_mag_sq_copy, r_mag_sq, 0) \ -, li_s( r_mag_sq, 31) \ -, sub_s( r_mag_sq, r_mag_sq, r_shift) \ -, shift_aright(r_mag_sq, r_mag_sq, 1) +#define mac_lzcr_round_even_half_shift(shift, mag_sq, mag_sq_copy) \ + and_i(shift, shift, gte_lzcr_even_mask) \ +, or_u(mag_sq_copy, mag_sq, 0) \ +, li_s( mag_sq, 31) \ +, sub_s( mag_sq, mag_sq, shift) \ +, shift_aright(mag_sq, mag_sq, 1) WORD_COUNT(mac_lzcr_round_even_half_shift, 5) #define mac_gte_general_purpose_interopolation(to_ir0, to_ir1, to_ir2, to_ir3, fr_mac1, fr_mac2, fr_mac3, nop_slot1, nop_slot2) \ diff --git a/code/duffle/gen/offsets.h b/code/duffle/gen/offsets.h index 51ebcc1..2bf5fde 100644 --- a/code/duffle/gen/offsets.h +++ b/code/duffle/gen/offsets.h @@ -16,7 +16,7 @@ // source: C:\projects\Pikuma\ps1\code\duffle\pad.c // source: C:\projects\Pikuma\ps1\code\duffle\math.atom.h // source: C:\projects\Pikuma\ps1\code\duffle\mips.atom.c -// source: C:\projects\Pikuma\ps1\code\duffle\gte.atom.c +// source: C:\projects\Pikuma\ps1\code\duffle\gte.atom.h // source: C:\projects\Pikuma\ps1\code\duffle\gp.atom.c // source: C:\projects\Pikuma\ps1\code\duffle\pad.atom.c // source: C:\projects\Pikuma\ps1\code\duffle\psyq.atom.c diff --git a/code/duffle/gp.h b/code/duffle/gp.h index 57a3550..9261267 100644 --- a/code/duffle/gp.h +++ b/code/duffle/gp.h @@ -6,16 +6,6 @@ * Primitive commands: gp0_cmd_poly_f3 = 0x20 (byte opcode) * Packed 32-bit cmd: gp0_word_poly_f3(r, g, b) (32-bit, shifted) * - * Type ordering: domain?_(direction)?_action_target_modifier_type? - * Examples: add_ui (add + unsigned + immediate) - * add_s (add + signed, R-type implicit) - * shift_lleft (shift + logical + left) - * shift_aright (shift + arithmetic + right) - * call_reg(rs) (call + register, $ra implicit) - * gte_mv_to_data_r (gte + mv + to + data + register) - * gte_lw_v0_xy(base) (gte + lw + v0 + xy) - * load_upper_i (load-upper + immediate, unique verb) - * * --- GPU-domain layer cake --- * Every gp.h macro follows the same 4-layer composition as mips.h and gte.h: * 4. Semantic encoders gp0_word_poly_f3(r,g,b) @@ -23,9 +13,6 @@ * 2. Per-field encoders enc_gp0_color_r(r), enc_gp0_color_g(g), ... * 1. Bitfield layout consts gp0_color_red_pos = 0, gp0_color_red_width = 8 * 0. Opcode IDs gp0_cmd_poly_f3 = 0x20 - * - * Vendor mnemonics (gte_mtc2, gte_mfc2, etc.) are NOT in this header. - * They live in the opt-in `gp_vendor_sym.h` for users who prefer the PSYQ-style names. * ============================================================================ */ #ifdef INTELLISENSE_DIRECTIVES @@ -391,10 +378,8 @@ enum { * Primitive structs (8 polygon variants + tag) * ============================================================================ * Each struct follows the GPU-documented memory layout for the corresponding primitive command. - * The PolyTag is the OT-link header; the rest of the struct is the primitive's body. + * PolyTag is an OT-link header. Rest of the struct is the primitive's body. * - * The current working layouts match the existing demo - * (floor_tri uses Poly_F3; cube_tri uses Poly_G4). * They are NOT necessarily byte-identical to the PSX-SPX reference layout. * The demo layout uses color+vertex interleaving that doesn't match the standard PSX SDK file format. * For PSX-SDK file compatibility, the textured variants (FT*, GT*) would need layout adjustments. diff --git a/code/duffle/gte.atom.c b/code/duffle/gte.atom.h similarity index 97% rename from code/duffle/gte.atom.c rename to code/duffle/gte.atom.h index 531dcbe..6886f4b 100644 --- a/code/duffle/gte.atom.c +++ b/code/duffle/gte.atom.h @@ -96,11 +96,11 @@ FI_ Slice_MipsCode ac_gte_sqr_v3(AtomBuilder_R ab, U4 r_sx, U4 r_sy, U4 r_sz, U4 }) /* ─── SQR FIRE — mtc2 3 GPRs into IR1/IR2/IR3, then fire SQR. ─── */ -FI_ Slice_MipsCode ac_gte_sqr_v3s4(AtomBuilder_R ab, Reg r_sx, Reg r_sy, Reg r_sz, MipsCode delay_slot) +FI_ Slice_MipsCode ac_gte_sqr_v3s4(AtomBuilder_R ab, Reg sx, Reg sy, Reg sz, MipsCode delay_slot) atom_dbg_skip MipsAtomComp_Proc_(ab, { - gte_mv_to_data_r(r_sx, C2_IR1), - gte_mv_to_data_r(r_sy, C2_IR2), - gte_mv_to_data_r(r_sz, C2_IR3), + gte_mv_to_data_r(sx, C2_IR1), + gte_mv_to_data_r(sy, C2_IR2), + gte_mv_to_data_r(sz, C2_IR3), delay_slot, gte_cmdw_sqr, }) @@ -157,16 +157,13 @@ FI_ Slice_MipsCode ac_trans_mt3s3s4(AtomBuilder_R ab * * Note: C2_LZCR (cop2r31) is a fixed read-only C2 data register — the caller must read it via mfc2 from C2_LZCR; * there is no register choice at the hardware level. Only the GPR that holds the result is caller-determined. */ -FI_ Slice_MipsCode ac_lzcr_round_even_half_shift(AtomBuilder_R ab, - U4 r_shift, - U4 r_mag_sq, - U4 r_mag_sq_copy) +FI_ Slice_MipsCode ac_lzcr_round_even_half_shift(AtomBuilder_R ab, Reg shift, Reg mag_sq, Reg mag_sq_copy) atom_dbg_skip MipsAtomComp_Proc_(ab, { - and_i(r_shift, r_shift, gte_lzcr_even_mask), - or_u(r_mag_sq_copy, r_mag_sq, 0), - li_s( r_mag_sq, 31), - sub_s( r_mag_sq, r_mag_sq, r_shift), - shift_aright(r_mag_sq, r_mag_sq, 1), + and_i(shift, shift, gte_lzcr_even_mask), + or_u(mag_sq_copy, mag_sq, 0), + li_s( mag_sq, 31), + sub_s( mag_sq, mag_sq, shift), + shift_aright(mag_sq, mag_sq, 1), }) FI_ Slice_MipsCode ac_gte_general_purpose_interopolation(AtomBuilder_R ab diff --git a/code/duffle/gte.h b/code/duffle/gte.h index 36ad134..6e52de0 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -1,21 +1,10 @@ /* ============================================================================ * duffle DSL Suffix Conventions * ============================================================================ - * * Every mnemonic in this header follows the same suffix grammar: * * Primitive commands: gp0_cmd_poly_f3 = 0x20 (byte opcode) * Packed 32-bit cmd: gp0_word_poly_f3(r, g, b) (32-bit, shifted) - * - * Type ordering: domain?_(direction)?_action_target_modifier_type? - * Examples: add_ui (add + unsigned + immediate) - * add_s (add + signed, R-type implicit) - * shift_lleft (shift + logical + left) - * shift_aright (shift + arithmetic + right) - * call_reg(rs) (call + register, $ra implicit) - * gte_mv_to_data_r (gte + mv + to + data + register) - * gte_lw_v0_xy(base) (gte + lw + v0 + xy) - * load_upper_i (load-upper + immediate, unique verb) * ============================================================================ */ #ifdef INTELLISENSE_DIRECTIVES @@ -29,21 +18,7 @@ /* ============================================================================ * gte.h — Geometry Transformation Engine (COP2) for the PS1 * ============================================================================ - * - * Hand-rolled DSL for emitting GTE/MIPS instruction words from C. - * No GCC inline-assembly string syntax in the code body. - * - * STYLE NOTES - * ----------- - * - Per-field encoders are named `enc_gte_(value)` and each one self-masks its argument before shifting. - * Mirrors the `enc_op / enc_rs / enc_rt / ...` family in mips.h. - * - The composite `enc_gte_cmdw(sf, mx, v, cv, lm, cmd)` is a flat OR of the per-field encoders, plus the COP2/CO base. - * - Pre-baked shortcuts (`gte_cmd_rtpt`, `gte_cmd_rtps`, …) are defined for the common cases so call sites read like assembly source. - * - All register/field values are enums (not `#define`s) so they show up in debugger symbol tables and IDE autocomplete. - * - * SEE ALSO - * -------- - * - mips.h: The MIPS encoder layer this builds on. + * DSL for emitting GTE/MIPS instruction words from C. */ /* C2 data registers */ diff --git a/code/duffle/memory.h b/code/duffle/memory.h index 1834182..dcebd0c 100644 --- a/code/duffle/memory.h +++ b/code/duffle/memory.h @@ -58,13 +58,13 @@ typedef Struct_(Str8) { UTF8* ptr; U4 len; }; typedef Struct_(Slice_Str8) { Str8* ptr; U4 len; }; #define slit(string_literal) (Str8){ (UTF8*) string_literal, S_(string_literal) - 1 } -typedef Struct_(Slice) { B1* ptr; U4 len; }; // Untyped Slice (byte-addressable; .len in elements) +typedef Struct_(Slice) { B1* ptr; U4 len; }; FI_ Slice slice_ut_(U4 ptr, U4 len) { return (Slice){(B1*)ptr, len}; } #define Slice_(type) Struct_(tmpl(Slice,type)) { type* ptr; U4 len; } typedef Slice_(B1); #define slice_assert(s) do { assert((s).ptr != 0); assert((s).len > 0); } while(0) -#define slice_end(slice) ((slice).ptr + S_slice(slice) / S_(B1)) /* byte-ptr arithmetic; .len is in elements per slice convention */ +#define slice_end(slice) ((slice).ptr + S_slice(slice) / S_(B1)) #define S_slice(s) ((s).len * S_((s).ptr[0])) #define slice_ut(ptr,len) slice_ut_(u4_(ptr), u4_(len)) @@ -134,8 +134,7 @@ FI_ U4 farena_unused_start(FArena arena) { return arena.start + arena.used; } #pragma region BIOS Scratchpad /* BIOS scratchpad location. 1 KB at 0x1F800000. - * TapeHostFrame occupies the final 44 bytes while tape code executes. - * Atom scratch is bounded by the TapeHostFrame_Loc declaration in lottes_tape.h. */ + * TapeHostFrame occupies the final 44 bytes while tape code executes. */ enum { Scratchpad_Loc = 0x1F800000, Scratchpad_Len = 0x400, /* 1 KB */ diff --git a/code/duffle/mips.h b/code/duffle/mips.h index a5c403f..eb080f4 100644 --- a/code/duffle/mips.h +++ b/code/duffle/mips.h @@ -80,14 +80,9 @@ enum { * Every R_* enum below has a parallel R_*_Code `#define` so that the preprocessor can stringify the integer * (e.g. for asm clobber lists and register-variable declarations via `rgcc(R_X)`). * The enum value is bound to the `#define` so the two forms cannot drift apart. - * - * Only registers that get stringified need a `_Code` form; the rest are plain enum values. - * If you need to add a new one, follow the pattern: - * #define R_T7_Code 15 - * R_T7 = R_T7_Code, // in the enum - * + * * User code should always reference the enum form (`R_T4`) at arithmetic sites and let - * `rlit(R_T4_Code)` / `rgcc(R_T4)` handle the stringify cases — never write the bare number `12`. + * `rlit(R_T4_Code)` / `rgcc(R_T4)` handle the stringify cases * ============================================================================ */ #define R_0_Code 0 #define R_AT_Code 1 diff --git a/code/duffle/pad.c b/code/duffle/pad.c index a2b28c1..2b4672e 100644 --- a/code/duffle/pad.c +++ b/code/duffle/pad.c @@ -6,16 +6,10 @@ # include "pad.h" #endif -/* Uses ONE 8-byte frame allocated via the compiler's standard prologue. +/* Uses an 8-byte frame allocated via the compiler's standard prologue. * 4 wasted-arg words for B(12h) InitPAD2 are at [SP+0..15] but are not explicitly allocated. * Compiler handles the MIPS O32 "wasted stack" convention for us by treating the B-call as a 4-arg call. - * - * The buffer pointers are passed as arguments so the compiler keeps them in callee-saved registers; - * The B(12h) asm volatile block does NOT clobber those registers (it clobbers only the volatile GPRs + B-table arg registers explicitly). - * The C-level writes after the call re-load the pointers from their callee-saved homes. - * - * The clobber list for both B-calls names the full BIOS destroy set documented in kernelbios.md:167-174 (R1..R15, R24..R25, R31, HI/LO). - * The kernel-ABI "volatile GPRs" subset is clb_mem_drain; the rest of the destroy set is enumerated explicitly here. */ + */ NI_ void pad_bios_init_start(PadBiosRaw* raw0, PadBiosRaw* raw1) { /* Pin raw0 + raw1 to $a0 + $a1 via rgcc; the B(12h) call uses these directly. @@ -24,9 +18,6 @@ NI_ void pad_bios_init_start(PadBiosRaw* raw0, PadBiosRaw* raw1) register PadBiosRaw* p1 rgcc(R_A1) = raw1; (void)p0; (void)p1; - // TODO(Ed): Properly annotate the raw values in the inline asm instructions. - // Use enums. - /* B(12h) InitPAD2(raw0, 0x22, raw1, 0x22) * $a0 = raw0 (rgcc-bound; survives the sequence below) * $a1 = raw1 (preserved into $a2 before $a1 is overwritten) diff --git a/code/hello_camera/hello_camera.atom.c b/code/hello_camera/hello_camera.atom.c index fa1016b..de9955e 100644 --- a/code/hello_camera/hello_camera.atom.c +++ b/code/hello_camera/hello_camera.atom.c @@ -11,8 +11,8 @@ # include "duffle/word_count.metadata.h" # include "duffle/psyq.h" # include "duffle/math.atom.h" +# include "duffle/gte.atom.h" # include "duffle/mips.atom.c" -# include "duffle/gte.atom.c" # include "duffle/gp.atom.c" # include "duffle/psyq.atom.c" # include "gen/offsets.h" @@ -21,7 +21,7 @@ # include "hello_camera.h" #endif -ATOM_FILE_DEBUGGER_LINE_MARKER(hello_joypad_atom_c); +ATOM_FILE_DEBUGGER_LINE_MARKER(hello_camera_atom_c); #pragma region MACs (Mips Atom components) diff --git a/code/hello_camera/hello_camera.c b/code/hello_camera/hello_camera.c index 29fe8e4..64d3f7f 100644 --- a/code/hello_camera/hello_camera.c +++ b/code/hello_camera/hello_camera.c @@ -34,7 +34,7 @@ #include "duffle/pad.c" #include "duffle/math.atom.h" #include "duffle/mips.atom.c" -#include "duffle/gte.atom.c" +#include "duffle/gte.atom.h" #include "duffle/gp.atom.c" #include "duffle/pad.atom.c" #include "duffle/psyq.atom.c"