Author SHA1 Message Date
ed 1faf3539d8 use tb_bind_ macro fro draw cube and tri, better type convention on binds. 2026-09-03 17:36:36 -04:00
ed 6b3fbab387 Adjusting type convention for raw memory. (Reviewing for articles)
Feel like opting for u1-4.. (b1-4 not meaning byte anymore, not sure why I bothered, just bools/bits)
2026-09-03 17:14:34 -04:00
ed 2c38a73709 Article writing review changes. 2026-09-01 00:55:07 -04:00
ed 159ead625e fixing weird identifiers... 2026-08-22 22:48:58 -04:00
ed 52888015de reviewing 2026-08-22 21:03:57 -04:00
22 changed files with 212 additions and 292 deletions
+2 -2
View File
@@ -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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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(...)
+17 -4
View File
@@ -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
@@ -120,6 +121,11 @@ typedef unsigned char TSet_(B1);
typedef __UINT16_TYPE__ TSet_(B2);
typedef __UINT32_TYPE__ TSet_(B4);
#define b1_(value) C_(B1, value)
#define b2_(value) C_(B2, value)
#define b4_(value) C_(B4, value)
#define u1_(value) C_(U1, value)
#define u2_(value) C_(U2, value)
#define u4_(value) C_(U4, value)
@@ -127,6 +133,13 @@ typedef __UINT32_TYPE__ TSet_(B4);
#define s2_(value) C_(S2, value)
#define s4_(value) C_(S4, value)
#define b1_r(value) C_(B1*R_, value)
#define b2_r(value) C_(B2*R_, value)
#define b4_r(value) C_(B4*R_, value)
#define b1_v(value) C_(B1 V_*, value)
#define b2_v(value) C_(B2 V_*, value)
#define b4_v(value) C_(B4 V_*, value)
#define u1_r(value) C_(U1 *R_, value)
#define u2_r(value) C_(U2 *R_, value)
#define u4_r(value) C_(U4 *R_, value)
-8
View File
@@ -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))
+12 -12
View File
@@ -13,13 +13,13 @@
// source: C:\projects\Pikuma\ps1\code\duffle\gte.h
// source: C:\projects\Pikuma\ps1\code\duffle\pad.h
// source: C:\projects\Pikuma\ps1\code\duffle\dsl.atom.h
// source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h
// source: C:\projects\Pikuma\ps1\code\duffle\tape.h
// source: C:\projects\Pikuma\ps1\code\duffle\bios.h
// source: C:\projects\Pikuma\ps1\code\duffle\psyq.h
// 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) \
+2 -2
View File
@@ -10,13 +10,13 @@
// source: C:\projects\Pikuma\ps1\code\duffle\gte.h
// source: C:\projects\Pikuma\ps1\code\duffle\pad.h
// source: C:\projects\Pikuma\ps1\code\duffle\dsl.atom.h
// source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h
// source: C:\projects\Pikuma\ps1\code\duffle\tape.h
// source: C:\projects\Pikuma\ps1\code\duffle\bios.h
// source: C:\projects\Pikuma\ps1\code\duffle\psyq.h
// 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
+2 -2
View File
@@ -1,14 +1,14 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "dsl.h"
# include "gp.h"
# include "lottes_tape.h"
# include "tape.h"
#endif
ATOM_FILE_DEBUGGER_LINE_MARKER(gp_atom_c);
#pragma region MACs (Mips Atom Components)
FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U4 cmd, U4 reg_transfer, U4 reg_base, U2 port)
FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U2 cmd, Reg reg_transfer, Reg reg_base, U2 port)
atom_dbg_skip MipsAtomComp_Proc_(ab, {
mac_load_word_imm(reg_transfer, cmd),
store_word( reg_transfer, reg_base, port),
+20 -35
View File
@@ -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,17 +378,15 @@ 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.
* ============================================================================ */
/* ---------- RGB8 (3-byte packed color) ---------- */
typedef Struct_(RGB8) { B1 r; B1 g; B1 b; };
typedef Struct_(RGB8) { U1 r; U1 g; U1 b; };
#define rgb8(r,g,b) ((RGB8){r,g,b})
/* ---------- PolyTag (the OT-link header; 1 word) ---------- */
@@ -431,7 +416,7 @@ typedef Struct_(PolyTag) {
typedef Struct_(Poly_F3) {
U4 tag;
RGB8 color;
B1 code;
U1 code;
union {
struct { V2_S2 p0; V2_S2 p1; V2_S2 p2; };
A3_V2_S2 points;
@@ -442,7 +427,7 @@ typedef Struct_(Poly_F3) {
typedef Struct_(Poly_F4) {
U4 tag;
RGB8 color;
B1 code;
U1 code;
union {
struct { V2_S2 p0; V2_S2 p1; V2_S2 p2; V2_S2 p3; };
A4_V2_S2 points;
@@ -451,18 +436,18 @@ typedef Struct_(Poly_F4) {
/* ---------- Poly_G3 (Gouraud Triangle; 7 words) ---------- */
typedef Struct_(Poly_G3) {
U4 tag; RGB8 c0; B1 code;
V2_S2 p0; RGB8 c1; B1 pad1;
V2_S2 p1; RGB8 c2; B1 pad2;
U4 tag; RGB8 c0; U1 code;
V2_S2 p0; RGB8 c1; U1 pad1;
V2_S2 p1; RGB8 c2; U1 pad2;
V2_S2 p2;
};
/* ---------- Poly_G4 (Gouraud Quad; 9 words) ---------- */
typedef Struct_(Poly_G4) {
U4 tag; RGB8 c0; B1 code;
V2_S2 p0; RGB8 c1; B1 pad1;
V2_S2 p1; RGB8 c2; B1 pad2;
V2_S2 p2; RGB8 c3; B1 pad3;
U4 tag; RGB8 c0; U1 code;
V2_S2 p0; RGB8 c1; U1 pad1;
V2_S2 p1; RGB8 c2; U1 pad2;
V2_S2 p2; RGB8 c3; U1 pad3;
V2_S2 p3;
};
@@ -471,7 +456,7 @@ typedef Struct_(Poly_G4) {
typedef Struct_(Poly_FT3) {
U4 tag;
RGB8 color;
B1 code;
U1 code;
U4 tpage;
U4 clut;
V2_S2 p0; U1 u0; U1 v0;
@@ -483,7 +468,7 @@ typedef Struct_(Poly_FT3) {
typedef Struct_(Poly_FT4) {
U4 tag;
RGB8 color;
B1 code;
U1 code;
U4 tpage;
U4 clut;
V2_S2 p0; U1 u0; U1 v0;
@@ -494,9 +479,9 @@ typedef Struct_(Poly_FT4) {
/* ---------- Poly_GT3 (Gouraud Textured Triangle) ---------- */
typedef Struct_(Poly_GT3) {
U4 tag; RGB8 c0; B1 code;
V2_S2 p0; RGB8 c1; B1 pad1;
V2_S2 p1; RGB8 c2; B1 pad2;
U4 tag; RGB8 c0; U1 code;
V2_S2 p0; RGB8 c1; U1 pad1;
V2_S2 p1; RGB8 c2; U1 pad2;
V2_S2 p2;
U4 tpage;
U4 clut;
@@ -507,10 +492,10 @@ typedef Struct_(Poly_GT3) {
/* ---------- Poly_GT4 (Gouraud Textured Quad) ---------- */
typedef Struct_(Poly_GT4) {
U4 tag; RGB8 c0; B1 code;
V2_S2 p0; RGB8 c1; B1 pad1;
V2_S2 p1; RGB8 c2; B1 pad2;
V2_S2 p2; RGB8 c3; B1 pad3;
U4 tag; RGB8 c0; U1 code;
V2_S2 p0; RGB8 c1; U1 pad1;
V2_S2 p1; RGB8 c2; U1 pad2;
V2_S2 p2; RGB8 c3; U1 pad3;
V2_S2 p3;
U4 tpage;
U4 clut;
@@ -3,7 +3,7 @@
# include "gen/offsets.h"
# include "gte.h"
# include "gp.h"
# include "lottes_tape.h"
# include "tape.h"
#endif
ATOM_FILE_DEBUGGER_LINE_MARKER(gte_atom_c);
@@ -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
@@ -267,10 +264,7 @@ internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804,
};
typedef Struct_(Binds_normalize_v3s4) {
U2 src_offset; /* offset of src V3_S4 within the BIOS scratchpad */
U2 dst_offset; /* offset of dst V3_S4 within the BIOS scratchpad */
};
typedef Struct_(Binds_normalize_v3s4) { U2 src_offset; U2 dst_offset; };
typedef Struct_(RegUse_normalize_v3s4) {
union { Reg_(V3_S4) res, src; };
union { Reg r0, src_ptr, mac2; };
@@ -339,21 +333,21 @@ typedef Struct_(Binds_gte_cross_v3s4) { V3_S4* src_a; V3_S4* src_b; V3_S4* out;
typedef Struct_(RegUse_gte_cross_v3s4) {
Reg_(V3_S4) a;
Reg_(V3_S4) b;
union { Reg out, t0; } x;
union { Reg src_a, t1, rt11; } y;
union { Reg src_b, t2, rt22; } z;
Reg out;
Reg src_a;
Reg src_b;
};
internal MipsAtom* gte_cross_v3s4(AtomArena_R aa, RegUse_gte_cross_v3s4 r)
atom_info(atom_bind(Binds_gte_cross_v3s4)) MipsAtom_Proc_(aa, {
load_word(r.y.src_a, R_TapePtr, O_(Binds_gte_cross_v3s4,src_a)),
load_word(r.z.src_b, R_TapePtr, O_(Binds_gte_cross_v3s4,src_b)),
load_word(r.x.out, R_TapePtr, O_(Binds_gte_cross_v3s4,out)),
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_gte_cross_v3s4)),
load_word(r.src_a, R_TapePtr, O_(Binds_gte_cross_v3s4,src_a)),
load_word(r.src_b, R_TapePtr, O_(Binds_gte_cross_v3s4,src_b)),
load_word(r.out, R_TapePtr, O_(Binds_gte_cross_v3s4,out)),
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_gte_cross_v3s4)),
mac_load_v3s4(r.a, r.y.src_a, 0), LdSlot_
mac_load_v3s4(r.b, r.z.src_b, 0), LdSlot_
mac_load_v3s4(r.a, r.src_a, 0), LdSlot_
mac_load_v3s4(r.b, r.src_b, 0), LdSlot_
mac_gte_op_cross_v3s4(r.a, r.b), /* RT diagonal + IR + OP + MAC read + shift */
mac_store_v3s4(r.a, r.x.out, 0),
mac_store_v3s4(r.a, r.out, 0),
mac_yield()
})
+1 -26
View File
@@ -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_<field>(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 */
+1 -1
View File
@@ -2,7 +2,7 @@
# include "gen/macs.h"
# include "gen/offsets.h"
# include "math.h"
# include "lottes_tape.h"
# include "tape.h"
#endif
ATOM_FILE_DEBUGGER_LINE_MARKER(math_atom_c);
+15 -16
View File
@@ -23,10 +23,10 @@ FI_ void mem_bump(U4 cap, U4*R_ used, U4 amount) {
used[0] += amount;
}
FI_ U4 mem_copy (U4 dest, U4 src, U4 len) { return (U4)(__builtin_memcpy ((void*)dest, (void const*)src, len)); }
FI_ U4 mem_copy_overlapping(U4 dest, U4 src, U4 len) { return (U4)(__builtin_memmove((void*)dest, (void const*)src, len)); }
FI_ U4 mem_fill (U4 dest, U4 value, U4 len) { return (U4)(__builtin_memset ((void*)dest, (int) value, len)); }
FI_ B4 mem_zero (U4 dest, U4 len) { if(dest == 0){return false;} mem_fill(dest, 0, len); return true; }
FI_ U4 mem_copy (U1_R dest, U1_R src, U4 len) { return (U4)(__builtin_memcpy ((void*)dest, (void const*)src, len)); }
FI_ U4 mem_copy_overlapping(U1* dest, U1* src, U4 len) { return (U4)(__builtin_memmove((void*)dest, (void const*)src, len)); }
FI_ U4 mem_fill (U1_R dest, U4 value, U4 len) { return (U4)(__builtin_memset ((void*)dest, (int) value, len)); }
FI_ B4 mem_zero (U1_R dest, U4 len) { if(dest == 0){return false;} mem_fill(dest, 0, len); return true; }
#pragma region DAG
@@ -58,31 +58,30 @@ 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)
FI_ Slice slice_ut_(U4 ptr, U4 len) { return (Slice){(B1*)ptr, len}; }
typedef Struct_(Slice) { U1* ptr; U4 len; };
FI_ Slice slice_ut_(U1* ptr, U4 len) { return (Slice){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))
#define S_slice(s) ((s).len * S_((s).ptr[0]))
#define slice_ut(ptr,len) slice_ut_(u4_(ptr), u4_(len))
#define slice_ut_arr(a) slice_ut_(u4_(a), S_(a))
#define slice_to_ut(s) slice_ut_(u4_((s).ptr), S_slice(s))
#define slice_ut(ptr,len) slice_ut_(C_(U1*,ptr), u4_(len))
#define slice_ut_arr(a) slice_ut_(C_(U1*,a), S_(a))
#define slice_to_ut(s) slice_ut_(C_(U1*,(s).ptr), S_slice(s))
#define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter)
#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = Array_decl(type,__VA_ARGS__), .len = Array_len( Array_decl(type,__VA_ARGS__)) }
#define slice_from_array(type, array) (tmpl(Slice,type)) { .ptr = array, .len = Array_len(array) }
FI_ void slice_zero_(Slice s) { slice_assert(s); mem_zero(u4_(s.ptr), s.len); }
FI_ void slice_zero_(Slice s) { slice_assert(s); mem_zero(s.ptr, s.len); }
#define slice_zero(s) slice_zero_(slice_to_ut(s))
FI_ void slice_copy_(Slice dest, Slice src) {
assert(S_slice(dest) >= S_slice(src));
slice_assert(dest);
slice_assert(src);
mem_copy(u4_(dest.ptr), u4_(src.ptr), S_slice(src));
mem_copy(dest.ptr, src.ptr, S_slice(src));
}
#define slice_copy(dest, src) do { \
static_assert(T_same(dest, src)); \
@@ -95,6 +94,7 @@ FI_ Slice slice_bump(U4_R used, U4 start, U4 len, U4 amount) {
return slice_ut(ptr, amount);
}
typedef Slice_(B1);
typedef Slice_(U1);
typedef Slice_(U4);
@@ -117,7 +117,7 @@ I_ Slice farena_push(FArena_R arena, U4 amount, Opt_farena o) {
U4 to_commit = align_pow2(desired, o.alignment ? o.alignment : MEM_ALIGNMENT_DEFAULT);
U4 ptr = arena->start + arena->used;
mem_bump(arena->capacity, & arena->used, to_commit);
return (Slice){ (B1*)ptr, to_commit };
return (Slice){ (U1*)ptr, to_commit };
}
FI_ void farena_reset (FArena_R arena) { arena->used = 0; }
FI_ void farena_rewind(FArena_R arena, U4 save_point) {
@@ -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 */
+1 -1
View File
@@ -3,7 +3,7 @@
# include "gen/offsets.h"
# include "bios.h"
# include "mips.h"
# include "lottes_tape.h"
# include "tape.h"
#endif
ATOM_FILE_DEBUGGER_LINE_MARKER(mips_atom_c);
+2 -7
View File
@@ -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
+1 -1
View File
@@ -3,7 +3,7 @@
# include "gen/offsets.h"
# include "mips.h"
# include "dsl.atom.h"
# include "lottes_tape.h"
# include "tape.h"
# include "pad.h"
#endif
+2 -11
View File
@@ -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)
@@ -121,7 +121,7 @@ typedef U2 Reg; // Register parameter used with atom or atom component procedure
typedef U4 const MipsCode; // Underlying type to mips asm words.
typedef Slice_(MipsCode);
typedef U4 const MipsAtom; // Underlying type to a mips atom defnition
typedef U4 const MipsAtom; // Underlying type to a mips atom definition
typedef Slice_(MipsAtom);
// Sometimes a user will define a bundle of atoms that represent a procedure of work as:
@@ -176,7 +176,7 @@ typedef Slice_(MipsAtom);
The constant is in `.rodata` so the linker may eliminate it. */
#define ATOM_FILE_DEBUGGER_LINE_MARKER(file_name) internal U4 const tmpl(atom_file_debugger_line_marker,file_name) = 0
typedef Slice_MipsAtom Tape;
typedef Struct_(Tape) { union { MipsAtom* ptr; U4* inlaid_data; }; U4 len; };
typedef Struct_(TapeHostFrame) {
U4 s0;
@@ -249,12 +249,8 @@ FI_ void tb_emit(TapeBuilder* tb, MipsAtom* atom) { u4_r(tb->ptr)[tb->used] = u4
FI_ void tb_data(TapeBuilder* tb, U4 data) { u4_r(tb->ptr)[tb->used] = u4_(data); ++ tb->used; }
#define tb_emit_(atom) tb_emit(& tb, atom)
FI_ void tb_bind(TapeBuilder* tb, Slice data) { mem_copy(tb->ptr + tb->used * S_(MipsCode), u4_(data.ptr), data.len); tb->used += data.len / S_(MipsCode); }
#define tb_bind_(tb,type,...) tb_bind(tb, (Slice){ (B1*)(& (type){__VA_ARGS__}), S_(type) }); static_assert(S_(type) % S_(MipsCode) == 0)
// NOTE(Ed): Wip still ideating convention. Possibly will never use a composite.
#define tb_emit_wbind_(tb,atom,...) tb_emit(tb,atom); tb_bind_(tb,tmpl(Binds,atom),__VA_ARGS__)
#define tb_emit_wbind2_(tb,atom,type,...) tb_emit(tb,atom); tb_bind_(tb,type,__VA_ARGS__)
FI_ void tb_bind(TapeBuilder* tb, Slice data) { mem_copy(b1_r(tb->ptr + tb->used * S_(MipsCode)), data.ptr, data.len); tb->used += data.len / S_(MipsCode); }
#define tb_bind_(tb,type,...) tb_bind(tb, (Slice){ (U1*)(& (type){__VA_ARGS__}), S_(type) }); static_assert(S_(type) % S_(MipsCode) == 0)
FI_ Tape tb_end (TapeBuilder* tb) { tb_emit(tb,tape_exit); return (Tape){ C_(U4*,tb->ptr), tb->used }; }
FI_ Tape tb_slice(TapeBuilder tb) { return (Tape){ C_(U4*,tb.ptr), tb.used }; }
@@ -262,6 +258,12 @@ FI_ Tape tb_slice(TapeBuilder tb) { return (Tape){ C_(U4
FI_ void tb_scope_run_end(TapeBuilder* tb) { tb_emit(tb,tape_exit); tape_run(tb_slice(tb[0])); }
#define tb_scope_run(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_scope_run_end(tb))
// NOTE(Ed): Wip still ideating convention. Possibly will never use a composite.
#define tb_emit_wbind_(tb,atom,...) tb_emit(tb,atom); tb_bind_(tb,tmpl(Binds,atom),__VA_ARGS__)
#define tb_emit_wbind2_(tb,atom,type,...) tb_emit(tb,atom); tb_bind_(tb,type,__VA_ARGS__)
#pragma endregion Tape Drive
#pragma region Macro Mips Atom Components
@@ -299,7 +301,7 @@ typedef Relative_(FArena) Struct_(AtomBuilder) { U4 start; U4 capacity; U4 used;
FI_ void atombuilder_push(AtomBuilder_R ab, Slice_MipsCode code) {
assert(ab->capacity - ab->used - code.len);
U4 dest = ab->start + ab->used * S_(MipsCode); U4 size = S_slice(code);
mem_copy(dest, u4_(code.ptr), size); ab->used += size;
mem_copy(b1_r(dest), b1_r(code.ptr), size); ab->used += size;
}
#define atombuilder_push_mac(ab, mac) atombuilder_push(ab, slice_arg_from_array(Slice_MipsCode, mac))
@@ -323,7 +325,7 @@ FI_ AtomArena atomarena_make(Slice mem) { AtomArena a; atomarena_init(& a, mem);
FI_ MipsAtom* atomarena_push(AtomArena_R aa, Slice_MipsCode code) {
assert(aa->capacity - aa->used - code.len);
U4 dest = atomarena_unused_start(aa[0]); U4 size = S_slice(code);
mem_copy(dest, u4_(code.ptr), size); aa->used += size;
mem_copy(b1_r(dest), b1_r(code.ptr), size); aa->used += size;
return C_(MipsAtom*, dest);
}
FI_ void atomarena_reset(AtomArena_R aa) { aa->used = 0; }
@@ -354,24 +356,16 @@ internal Reg const regfile_alloc_order[] = {
R_T8, R_T9,
};
typedef Struct_(RegFile) {
A2_U2 GPR;
A2_U2 GTE;
};
typedef Struct_(RegFile) { A2_U2 GPR; };
#define regfile(pin_mask) {.GPR={u4_lo(pin_mask), u4_hi(pin_mask)} }
FI_ void regfile_init(RegFile_R rf) {
/* pack the 32-bit ABI mask into the two U2s */
rf->GPR[0] = u4_lo(regfile_abi_mask);
rf->GPR[1] = u4_hi(regfile_abi_mask);
rf->GTE[0] = rf->GTE[1] = 0;
}
FI_ RegFile regfile_make(void) { RegFile rf; regfile_init(& rf); return rf; }
typedef Struct_(RegFile_RInfo) {
U2_R section;
U2 mask;
B2 occupied;
};
typedef Struct_(RegFile_RInfo) { U2_R section; U2 mask; B2 occupied; };
FI_ RegFile_RInfo regfile_rinfo(A2_U2 file, Reg r_id) {
U2 s_id = r_id >> 4;
U2_R section = & file[s_id];
@@ -381,15 +375,11 @@ FI_ RegFile_RInfo regfile_rinfo(A2_U2 file, Reg r_id) {
}
FI_ Reg regfile__alloc_helper(A2_U2 file, Reg r_id) {
Reg result = 0; RegFile_RInfo info = regfile_rinfo(file, r_id);
if (info.occupied == false) {
info.section[0] |= info.mask;
result = r_id;
}
if (info.occupied == false) { info.section[0] |= info.mask; result = r_id; }
return result;
}
I_ Reg regfile_alloc(RegFile_R rf) {
Reg allocated = 0;
for index_iter(U4, r_id, R_V0, <, R_T9) {
I_ Reg regfile_alloc(RegFile_R rf) {
Reg allocated = 0; for index_iter(U4, r_id, R_V0, <, R_T9) {
allocated = regfile__alloc_helper(rf->GPR, r_id);
Jmp_nZero_(allocated,resolved);
}
@@ -398,13 +388,12 @@ resolved: return allocated;
}
FI_ Reg regfile_pin(RegFile_R rf, Reg r_id) {
RegFile_RInfo info = regfile_rinfo(rf->GPR, r_id);
assert(info.occupied == false);
assert(info.occupied == false);
info.section[0] |= info.mask;
return r_id;
}
FI_ void regfile_pin_mask(RegFile_R rf, U4 mask) {
B4 occupied = u4_r(rf->GPR)[0] & mask;
assert(occupied == false);
B4 occupied = u4_r(rf->GPR)[0] & mask; assert(occupied == false);
u4_r(rf->GPR)[0] |= mask;
}
FI_ void regfile_free_mask(RegFile_R rf, U4 mask) {
@@ -412,8 +401,7 @@ FI_ void regfile_free_mask(RegFile_R rf, U4 mask) {
u4_r(rf->GPR)[0] &= ~mask;
}
FI_ void regfile_free_reg(RegFile_R rf, Reg r_id) {
/* never free the ABI set */
if (regfile_abi_mask & (1u << r_id)) return;
if (regfile_abi_mask & (1u << r_id)) return; // never free the ABI set
RegFile_RInfo info = regfile_rinfo(rf->GPR, r_id);
info.section[0] &= ~info.mask;
}
@@ -447,7 +435,6 @@ FI_ void regfile_reset_to_mask(RegFile_R rf, U4 mask) {
add_si(r.t1.view_3, r.usual_modifiable, 10),
mac_yield(),
})
#pragma endregion Mips Atom Procs
#pragma region Baked Mips Atoms
+29 -33
View File
@@ -3,7 +3,7 @@
# include "duffle/gen/macs.h"
# include "duffle/gen/offsets.h"
# include "duffle/dsl.atom.h"
# include "duffle/lottes_tape.h"
# include "duffle/tape.h"
# include "duffle/mips.h"
# include "duffle/gte.h"
# include "duffle/gp.h"
@@ -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)
@@ -237,8 +237,8 @@ enum {
};
//screen_env_init. Mirrors the libpsyx's SetDefDispEnv + SetDefDrawEnv + the manual enable_auto_clear / initial_bg_color writes.
internal MipsAtom_(screen_env_init) atom_info(atom_phase(screen_init)
, atom_reads(R_T0, R_ScreenX, R_ScreenY, R_ScreenBuf)
, atom_writes(R_T0, R_ScreenX, R_ScreenY)
, atom_reads(R_ScreenBuf)
, atom_writes(R_ScreenBuf)
) {
/* display[0] = (0, 0, 320, 240); rest of struct zeroed. */
add_ui(R_ScreenX, R_0, ScreenRes_X), add_ui(R_ScreenY, R_0, ScreenRes_Y),
@@ -441,7 +441,7 @@ typedef Struct_(Binds_PadInputCam) {
Camera* cam;
};
internal MipsAtom_(pad_input_cam) atom_info(atom_bind(Binds_PadInputCam)
, atom_reads( R_Cam, R_CamPadState, R_TapePtr)
, atom_reads( R_Cam, R_CamPadState)
, atom_writes(R_Cam)
) {
/* Bind pop: state → R_CamPadState (R_T5), cam → R_Cam (R_T4), advance R_TapePtr by 8. */
@@ -499,20 +499,17 @@ enum {
#define R_OtBase_Code R_T6_Code
};
typedef Struct_(Binds_CubeTri) {
U4 PrimCursor;
V4_S2* FaceCursor;
V3_S2* VertBase;
U4* OtBase;
U1* prim_cursor;
V4_S2* face_cursor;
V3_S2* vert_base;
U4* ot_base;
};
internal MipsAtom_(rbind_cube_g4_face) atom_info(atom_bind(Binds_CubeTri), atom_phase(cube_g4)
, atom_reads(R_TapePtr)
, atom_writes(R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase, R_TapePtr)
){
internal MipsAtom_(rbind_cube_g4_face) atom_info(atom_bind(Binds_CubeTri), atom_phase(cube_g4)){
/* 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)),
load_word(R_PrimCursor, R_TapePtr, O_(Binds_CubeTri,prim_cursor)),
load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,face_cursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,vert_base)),
load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,ot_base)),
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_CubeTri)),
mac_yield()
};
@@ -530,11 +527,11 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
LdSlot_ mac_gte_load_tri_verts(R_VertBase, R_T0, R_T1, R_T2),
GteDelay_ load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)), LdSlot_
GteDelay_ load_word(R_AtomJmp, R_TapePtr, 0), LdSlot_ //ac_yield: word 2,
GteDelay_ load_word(R_AtomJmp, R_TapePtr, 0), LdSlot_ //ac_yield: word 1,
gte_cmdw_rotate_translate_perspective_triple,
gte_cmdw_nclip,
gte_mv_from_data_r(R_T0, C2_MAC0), GteDelay_ add_ui_self(R_TapePtr, S_(MipsCode)), // ac_yield: word 1
gte_mv_from_data_r(R_T0, C2_MAC0), GteDelay_ add_ui_self(R_TapePtr, S_(MipsCode)), // ac_yield: word 2
branch_le_zero(R_T0, atom_offset(cull, cube_g4_face_exit)),
/* BD-slot: Write the prim tag (R_0=0; overwrites the legacy tag word in the prim_buffer).
* If branch IS taken (face culled), the body is skipped and this 0-tag is stranded —
@@ -564,16 +561,16 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
// end: branch(cull)
atom_label(cube_g4_face_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 */
add_ui_self(R_PrimCursor, S_(Poly_G4)), // 9 words = Poly_G4
add_ui_self(R_FaceCursor, S_(S2) * 4), // 4 × S2 = 8 bytes
jump_reg(R_AtomJmp), BdSlot_ nop // ac_yield: word 3-4
};
typedef Struct_(Binds_FloorTri) {
U4 PrimCursor;
V3_S2* FaceCursor;
V3_S2* VertBase;
U4* OtBase;
U1* prim_cursor;
V3_S2* face_cursor;
V3_S2* vert_base;
U4* ot_base;
};
internal
MipsAtom_(rbind_floor_f3_face) atom_info(atom_bind(Binds_FloorTri), atom_phase(floor_f3)
@@ -581,10 +578,10 @@ MipsAtom_(rbind_floor_f3_face) atom_info(atom_bind(Binds_FloorTri), atom_phase(f
, atom_writes(R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase, R_TapePtr)
){
/* 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)),
load_word(R_PrimCursor, R_TapePtr, O_(Binds_FloorTri,prim_cursor)),
load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,face_cursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,vert_base)),
load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,ot_base)),
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_FloorTri)),
mac_yield()
};
@@ -626,10 +623,9 @@ atom_label(floor_f3_face_exit)
jump_reg(R_AtomJmp), BdSlot_ nop // ac_yield: word 3-4
};
typedef Struct_(Binds_SyncPrimitiveArena) { U4 used; U4 cursor; };
typedef Struct_(Binds_SyncPrimitiveArena) { U4* used; U1* cursor; };
internal MipsAtom_(sync_primitive_arena) atom_info(atom_bind(Binds_SyncPrimitiveArena)
, atom_reads( R_TapePtr, R_PrimCursor)
, atom_writes(R_TapePtr)
, atom_reads(R_PrimCursor), atom_writes(R_AT)
){
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,used)),
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,cursor)), LdSlot_
+53 -60
View File
@@ -24,7 +24,7 @@
#include "duffle/pad.h"
#include "duffle/dsl.atom.h"
#include "duffle/lottes_tape.h"
#include "duffle/tape.h"
#include "duffle/bios.h"
#include "duffle/psyq.h"
@@ -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"
@@ -93,11 +93,11 @@ extern SMemory smem;
#define pad0_btn_(btn) btn & smem.pad[0].buttons
#define pad1_btn_(btn) btn & smem.pad[1].buttons
I_ B1* prim__alloc(U4 type_width, Str8 type_name) {
I_ U1* prim__alloc(U4 type_width, Str8 type_name) {
gknown PrimitiveArena* pa = & smem.primitives;
gknown B1* buf = (B1*) r_(smem.primitives.buf)[smem.active_buf_id];
gknown U1* buf = (U1*) r_(smem.primitives.buf)[smem.active_buf_id];
assert(pa->used + type_width < PrimitiveBuff_Len);
B1* next = buf + pa->used;
U1* next = buf + pa->used;
pa->used += type_width;
return next;
}
@@ -138,11 +138,11 @@ internal void compile_init_atoms(void) {
smem.gte_cross_v3s4 = gte_cross_v3s4(& ab,
RegUse_(gte_cross_v3s4) {
.a = ralloc_v3(),
.b = ralloc_v3(),
.x = ralloc(),
.y = ralloc(),
.z = ralloc(),
.a = ralloc_v3(),
.b = ralloc_v3(),
.out = ralloc(),
.src_a = ralloc(),
.src_b = ralloc(),
});
regfile_reset(& rf);
@@ -241,29 +241,18 @@ FI_ void camera_look_at(TapeBuilder_R tb, Camera* c, P3_S4* target, V3_S4* up_in
void update(PrimitiveArena* pa, U4* ordering_buf)
{
TapeBuilder tb = tb_make(slice_ut_arr(smem.MemTape));
// Pad Input
{
/*Pad Input*/ {
tb.used = 0; tb_scope_run(& tb) {
// Grab latest state from bios.
tb_emit_(pad_bios_snapshot);
tb_data(& tb, u4_(& smem.pad_raw[0]));
tb_data(& tb, u4_(& smem.pad_raw[0]));
tb_data(& tb, u4_(& smem.pad[0]));
// tb_emit_(pad_bios_snapshot);
// tb_data_(raw, & smem.pad_raw[1]);
// tb_data_(state, & smem.pad[1]);
tb_emit_(pad_input_cam);
tb_data(& tb, u4_(& smem.pad[0]));
tb_data(& tb, u4_(& smem.cam));
// tb_emit_(pad_input_cube_rotation);
// tb_data_(state, & smem.pad[0]);
// tb_data_(cube_rot, & smem.cube.rot);
// tb_data_(floor_rot, & smem.floor.rot);
}
}
orderingtbl_clear_reverse(ordering_buf, OrderingTbl_Len);
// Update the position based on acceleration and velocity
@@ -298,33 +287,28 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
mt3s2s4_rotation (& smem.cube.rot, & smem.tform_world);
mt3s2s4_translation(& smem.tform_world, & smem.cube.pos);
mt3s2s4_scale (& smem.tform_world, & smem.cube.scale);
// Combine world and look_at matrix.
gte_comp_coord_m3s2(& smem.cam.look_at, & smem.tform_world, & smem.tform_view);
gte_matrix_set_rotation (& smem.tform_view);
gte_matrix_set_translation(& smem.tform_view);
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
U4 prim_cursor = prim_base + pa->used;
tb.used = 0; tb_scope(& tb) {
tb_emit(& tb, rbind_cube_g4_face);
tb_data(& tb, prim_cursor);
tb_data(& tb, u4_(smem.cube.faces));
tb_data(& tb, u4_(smem.cube.verts));
tb_data(& tb, u4_(ordering_buf));
U1* prim_base = u1_r(pa->buf[smem.active_buf_id]);
U1* prim_cursor = prim_base + pa->used;
tb.used = 0; tb_scope_run(& tb) {
tb_emit(& tb, rbind_cube_g4_face); tb_bind_(& tb, Binds_CubeTri,
.prim_cursor = prim_cursor,
.face_cursor = smem.cube.faces,
.vert_base = smem.cube.verts,
.ot_base = ordering_buf,
);
for (U4 i = 0; i < Cube_num_faces; i++) {
// Two triangles per quad face: (x,y,z) and (x,z,w)
tb_emit(& tb, cube_g4_face);
tb_emit(& tb, cube_g4_face); // Two triangles per quad face: (x,y,z) and (x,z,w)
}
tb_emit(& tb, sync_primitive_arena);
tb_data(& tb, u4_(& pa->used));
tb_data(& tb, prim_base);
tb_emit(& tb, sync_primitive_arena); tb_bind_(& tb, Binds_SyncPrimitiveArena,
.used = & pa->used,
.cursor = prim_base,
);
}
tape_run(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
// smem.cube.rot.y += 30;
}
// Draw floor
@@ -340,33 +324,29 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
gte_matrix_set_rotation (& smem.tform_view);
gte_matrix_set_translation(& smem.tform_view);
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
U4 prim_cursor = prim_base + pa->used;
U1_R prim_base = u1_r(pa->buf[smem.active_buf_id]);
U1_R prim_cursor = prim_base + pa->used;
// 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)
tb.used = 0; tb_scope(& tb) {
// tb_emit(& tb, set_gte_mt3s2s4);
// tb_data(& tb, u4_(& smem.tform_view));
tb_emit(& tb, rbind_floor_f3_face);
// TODO(Ed): Just use a single context struct ref?
tb_data(& tb, prim_cursor);
tb_data(& tb, u4_(smem.floor.faces));
tb_data(& tb, u4_(smem.floor.verts));
tb_data(& tb, u4_(ordering_buf));
tb.used = 0; tb_scope_run(& tb) {
tb_emit(& tb, rbind_floor_f3_face); tb_bind_(& tb, Binds_FloorTri,
.prim_cursor = prim_cursor,
.face_cursor = smem.floor.faces,
.vert_base = smem.floor.verts,
.ot_base = ordering_buf,
);
for (U4 i = 0; i < Floor_num_faces; i++) {
tb_emit(& tb, floor_f3_face);
}
// After floor_f3_face iterations complete, the primitive arena's used counter needs updating.
tb_emit(& tb, sync_primitive_arena);
tb_data(& tb, u4_(& pa->used));
tb_data(& tb, prim_base);
tb_emit(& tb, sync_primitive_arena); tb_bind_(& tb, Binds_SyncPrimitiveArena,
.used = & pa->used,
.cursor = prim_base,
);
}
tape_run(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
// C-side state (pa->used) has already been updated by the tape!
// smem.floor.rot.y += 5;
}
@@ -390,6 +370,19 @@ void gp_display_frame(DoubleBuffer* screen_buf, S4* active_buf_id, U4* ordering_
int main(void)
{
smem = (SMemory){0};
B4 basic_sample = false; if (basic_sample) {
// We will be defining the tape here along with its atom, then running the tape after.
TapeBuilder tb = tb_make(slice_ut_arr(smem.MemTape));
MipsCode add_one_to_R_T1[] = {
add_ui_self(R_T1, 1),
mac_yield(),
};
tb_emit(& tb, C_(MipsAtom*, add_one_to_R_T1));
Tape tape = tb_end(& tb);
tape_run(tape);
}
// smem.primitives.used = 0;
// smem.active_buf_id = 0;
smem.cam.pos = v3s4(500, -1000, -1500);
+8 -8
View File
@@ -24,7 +24,7 @@ enum {
typedef U4 OrderingTable_Buffer[OrderingTbl_Len];
typedef Array_(OrderingTable_Buffer, 2);
typedef B1 PrimitiveBuffer[PrimitiveBuff_Len];
typedef U1 PrimitiveBuffer[PrimitiveBuff_Len];
typedef Array_(PrimitiveBuffer, 2);
typedef Struct_(PrimitiveArena) {
A2_PrimitiveBuffer buf;
@@ -54,14 +54,14 @@ I_ void ent_cube128_init(A8_V3_S2* verts, A6_V4_S2* faces) {
{ 2, 3, 6, 7 },
{ 3, 0, 7, 4 },
};
mem_copy(u4_(verts), u4_(& baked_verts), S_(A8_V3_S2) );
mem_copy(u4_(faces), u4_(& baked_faces), S_(A6_V4_S2) );
mem_copy(b1_r(verts), b1_r(& baked_verts), S_(A8_V3_S2) );
mem_copy(b1_r(faces), b1_r(& baked_faces), S_(A6_V4_S2) );
return;
}
typedef Struct_(Ent_Cube) {
V3_S4 accel;
V3_S4 vel;
V3_S4 pos; // RGA(Lengyel): affine point with implicit weight one. Storage alias of V3_S4.
V3_S4 pos;
V3_S4 scale;
V3_S2 rot;
A8_V3_S2 verts;
@@ -83,12 +83,12 @@ I_ void ent_floor_init(A4_V3_S2* verts, A2_V3_S2* faces) {
{ 0, 1, 2 },
{ 1, 3, 2 },
};
mem_copy(u4_(verts), u4_(& baked_verts), S_(A4_V3_S2));
mem_copy(u4_(faces), u4_(& baked_faces), S_(A2_V3_S2));
mem_copy(b1_r(verts), b1_r(& baked_verts), S_(A4_V3_S2));
mem_copy(b1_r(faces), b1_r(& baked_faces), S_(A2_V3_S2));
};
typedef Struct_(Ent_Floor) {
V3_S4 accel;
V3_S4 pos; // RGA(Lengyel): affine point with implicit weight one. Storage alias of V3_S4.
V3_S4 pos;
V3_S4 scale;
V3_S2 rot;
A4_V3_S2 verts;
@@ -96,7 +96,7 @@ typedef Struct_(Ent_Floor) {
};
typedef Struct_(Camera) {
P3_S4 pos; // RGA(Lengyel): affine point with implicit weight one. Storage alias of V3_S4.
P3_S4 pos;
V3_S2 rot;
MT3_S2S4 look_at;
};