mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-09-22 17:20:04 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a37ffe6f58 | ||
|
|
b61610d819 | ||
|
|
1b950ab5b5 | ||
|
|
b2858b3c73 | ||
|
|
f1801343e2 | ||
|
|
85b2205603 | ||
|
|
2d754650c9 |
@@ -160,6 +160,8 @@
|
|||||||
* ----------------------------------------------------------------------------*/
|
* ----------------------------------------------------------------------------*/
|
||||||
#define atom_bind(binds_struct) /* atom_bind(binds_struct) */
|
#define atom_bind(binds_struct) /* atom_bind(binds_struct) */
|
||||||
|
|
||||||
|
#define Binds_(type) (tmpl(Binds,type)) // TODO(Ed): Do we want to use this?
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
* atom_label / atom_offset — branch target machinery
|
* atom_label / atom_offset — branch target machinery
|
||||||
*
|
*
|
||||||
@@ -177,9 +179,3 @@
|
|||||||
#define atom_offset(F, T) atom_offset_ ## F ## _ ## T
|
#define atom_offset(F, T) atom_offset_ ## F ## _ ## T
|
||||||
// atom_label is a pure annotation for the metaprogram's offset calculations.
|
// atom_label is a pure annotation for the metaprogram's offset calculations.
|
||||||
#define atom_label(name) /* atom_label anchor: name */
|
#define atom_label(name) /* atom_label anchor: name */
|
||||||
|
|
||||||
// WIP: Atoms Assocated closely with each other to form a tape procedure. (Maybe also a phase in a procedure/pipeline?)
|
|
||||||
|
|
||||||
#define AtomBundle_(name) Struct_(tmpl(AtomBundle,name))
|
|
||||||
#define AtomBundle_Len(name) S_(tmpl(AtomBundle,name))/S_(MipsAtom*)
|
|
||||||
#define AtomBundleEntry_(bundle,entry) tmpl(bundle,entry)
|
|
||||||
|
|||||||
@@ -228,21 +228,21 @@ WORD_COUNT(mac_gte_op_cross_v3s4, 13)
|
|||||||
WORD_COUNT(mac_gte_store_f3, 3)
|
WORD_COUNT(mac_gte_store_f3, 3)
|
||||||
|
|
||||||
/* atom_dbg_skip */
|
/* atom_dbg_skip */
|
||||||
#define mac_gte_load_tri_verts(r_vert_base, r_v0, r_v1, r_v2) \
|
#define mac_gte_load_tri_verts(vbase, v0, v1, v2) \
|
||||||
shift_lleft(R_AT, r_v0, v3s2_byteoff) \
|
shift_lleft(R_AT, v0, v3s2_byteoff) \
|
||||||
, add_u_self(R_AT, r_vert_base) \
|
, add_u_self(R_AT, vbase) \
|
||||||
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
||||||
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
||||||
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY0) \
|
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY0) \
|
||||||
, gte_mv_to_data_r(R_V1, C2_VZ0) \
|
, gte_mv_to_data_r(R_V1, C2_VZ0) \
|
||||||
, shift_lleft(R_AT, r_v1, v3s2_byteoff) \
|
, shift_lleft(R_AT, v1, v3s2_byteoff) \
|
||||||
, add_u_self(R_AT, r_vert_base) \
|
, add_u_self(R_AT, vbase) \
|
||||||
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
||||||
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
||||||
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY1) \
|
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY1) \
|
||||||
, gte_mv_to_data_r(R_V1, C2_VZ1) \
|
, gte_mv_to_data_r(R_V1, C2_VZ1) \
|
||||||
, shift_lleft(R_AT, r_v2, v3s2_byteoff) \
|
, shift_lleft(R_AT, v2, v3s2_byteoff) \
|
||||||
, add_u_self(R_AT, r_vert_base) \
|
, add_u_self(R_AT, vbase) \
|
||||||
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
, load_word(R_V0, R_AT, O_(V3_S2,x)) \
|
||||||
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
, load_word(R_V1, R_AT, O_(V3_S2,z)) \
|
||||||
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY2) \
|
, LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY2) \
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ enum {
|
|||||||
atom_offset_example_atom_proc_skip = _atom_offset_example_atom_proc_skip,
|
atom_offset_example_atom_proc_skip = _atom_offset_example_atom_proc_skip,
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- atom: build_normalize_v3s4 (63 words) ---
|
// --- atom: normalize_v3s4 (62 words) ---
|
||||||
|
|
||||||
#define _atom_offset_aligned_done_srav_path 3
|
#define _atom_offset_aligned_done_srav_path 3
|
||||||
#define _atom_offset_srav_path_aligned_done 4
|
#define _atom_offset_srav_path_aligned_done 4
|
||||||
|
|||||||
+13
-14
@@ -63,10 +63,10 @@ FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom
|
|||||||
})
|
})
|
||||||
|
|
||||||
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE */
|
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE */
|
||||||
I_ Slice_MipsCode ac_gte_load_tri_verts(AtomBuilder_R ab, U4 r_vert_base, U4 r_v0, U4 r_v1, U4 r_v2) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
I_ Slice_MipsCode ac_gte_load_tri_verts(AtomBuilder_R ab, Reg vbase, Reg v0, Reg v1, Reg v2) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||||
shift_lleft(R_AT, r_v0, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0),
|
shift_lleft(R_AT, v0, v3s2_byteoff), add_u_self(R_AT, vbase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0),
|
||||||
shift_lleft(R_AT, r_v1, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1),
|
shift_lleft(R_AT, v1, v3s2_byteoff), add_u_self(R_AT, vbase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1),
|
||||||
shift_lleft(R_AT, r_v2, v3s2_byteoff), add_u_self(R_AT, r_vert_base), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2),
|
shift_lleft(R_AT, v2, v3s2_byteoff), add_u_self(R_AT, vbase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), LdSlot_ gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2),
|
||||||
})
|
})
|
||||||
|
|
||||||
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices of the
|
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices of the
|
||||||
@@ -267,28 +267,28 @@ internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
|
|||||||
0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804,
|
0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Struct_(Binds_NormalizeV3S4) {
|
typedef Struct_(Binds_normalize_v3s4) {
|
||||||
U2 src_offset; /* offset of src V3_S4 within the BIOS scratchpad */
|
U2 src_offset; /* offset of src V3_S4 within the BIOS scratchpad */
|
||||||
U2 dst_offset; /* offset of dst V3_S4 within the BIOS scratchpad */
|
U2 dst_offset; /* offset of dst V3_S4 within the BIOS scratchpad */
|
||||||
};
|
};
|
||||||
typedef Struct_(RegUse_build_normalize_v3s4) {
|
typedef Struct_(RegUse_normalize_v3s4) {
|
||||||
union { Reg_(V3_S4) res, src; };
|
union { Reg_(V3_S4) res, src; };
|
||||||
union { Reg r0, src_ptr, mac2; };
|
union { Reg r0, src_ptr, mac2; };
|
||||||
union { Reg r1, dst_ptr; };
|
union { Reg r1, dst_ptr; };
|
||||||
union { Reg r2, dst_offset, mac1, v_sqr_aligned; };
|
union { Reg r2, dst_offset, mac1, v_sqr_aligned; };
|
||||||
union { Reg r3, src_offset, btarget, shift_count, sqrtbl_index; };
|
union { Reg r3, src_offset, btarget, shift_count, sqrtbl_index; };
|
||||||
union { Reg r4, mac3, v_sqr_sum, half_shift_tmp, inv_len; };
|
union { Reg r4, mac3, v_sqr_sum, scale_exp, srav_shift; };
|
||||||
union { Reg r5, lzcr, half_shift; };
|
union { Reg r5, lzcr, inv_len; };
|
||||||
};
|
};
|
||||||
/* ─── Full normalize (all 4 stages inline) ───
|
/* ─── Full normalize (all 4 stages inline) ───
|
||||||
* Generic 4-stage GTE normalize (SQR → sum+LZCR → align+sqrtbl → GPF+srav). */
|
* Generic 4-stage GTE normalize (SQR → sum+LZCR → align+sqrtbl → GPF+srav). */
|
||||||
internal MipsAtom* build_normalize_v3s4(AtomArena_R aa, RegUse_build_normalize_v3s4 r)
|
internal MipsAtom* normalize_v3s4(AtomArena_R aa, RegUse_normalize_v3s4 r)
|
||||||
MipsAtom_Proc_(aa, {
|
MipsAtom_Proc_(aa, {
|
||||||
load_half(r.src_offset, R_TapePtr, O_(Binds_NormalizeV3S4, src_offset)),
|
load_half(r.src_offset, R_TapePtr, O_(Binds_normalize_v3s4, src_offset)),
|
||||||
load_half(r.dst_offset, R_TapePtr, O_(Binds_NormalizeV3S4, dst_offset)),
|
load_half(r.dst_offset, R_TapePtr, O_(Binds_normalize_v3s4, dst_offset)),
|
||||||
LdSlot_ add_u(r.src_ptr, R_ScratchBase, r.src_offset),
|
LdSlot_ add_u(r.src_ptr, R_ScratchBase, r.src_offset),
|
||||||
LdSlot_ add_u(r.dst_ptr, R_ScratchBase, r.dst_offset),
|
LdSlot_ add_u(r.dst_ptr, R_ScratchBase, r.dst_offset),
|
||||||
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_NormalizeV3S4)),
|
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_normalize_v3s4)),
|
||||||
|
|
||||||
mac_load_v3s4(r.src, r.src_ptr, 0),
|
mac_load_v3s4(r.src, r.src_ptr, 0),
|
||||||
|
|
||||||
@@ -313,7 +313,6 @@ MipsAtom_Proc_(aa, {
|
|||||||
sub_s(r.shift_count, r.shift_count, r.lzcr),
|
sub_s(r.shift_count, r.shift_count, r.lzcr),
|
||||||
shift_aright_var(r.v_sqr_aligned, r.v_sqr_aligned, r.shift_count),
|
shift_aright_var(r.v_sqr_aligned, r.v_sqr_aligned, r.shift_count),
|
||||||
atom_label(aligned_done)
|
atom_label(aligned_done)
|
||||||
or_u(r.half_shift, r.half_shift_tmp, 0),
|
|
||||||
add_si( r.v_sqr_aligned, r.v_sqr_aligned, -64),
|
add_si( r.v_sqr_aligned, r.v_sqr_aligned, -64),
|
||||||
shift_lleft(r.v_sqr_aligned, r.v_sqr_aligned, 1),
|
shift_lleft(r.v_sqr_aligned, r.v_sqr_aligned, 1),
|
||||||
mac_load_word_imm(r.sqrtbl_index, & gte_normalize_sqr_tbl), add_u_self(r.sqrtbl_index, r.v_sqr_aligned),
|
mac_load_word_imm(r.sqrtbl_index, & gte_normalize_sqr_tbl), add_u_self(r.sqrtbl_index, r.v_sqr_aligned),
|
||||||
@@ -326,7 +325,7 @@ MipsAtom_Proc_(aa, {
|
|||||||
GteDelay_ load_word(R_AtomJmp, R_TapePtr, 0), LdSlot_ // ac_yield: word 1
|
GteDelay_ load_word(R_AtomJmp, R_TapePtr, 0), LdSlot_ // ac_yield: word 1
|
||||||
GteDelay_ add_ui_self( R_TapePtr, S_(MipsCode)) // ac_yield: word 2
|
GteDelay_ add_ui_self( R_TapePtr, S_(MipsCode)) // ac_yield: word 2
|
||||||
),
|
),
|
||||||
mac_shift_aright_var_v3s4_self(r.res, r.half_shift),
|
mac_shift_aright_var_v3s4_self(r.res, r.srav_shift),
|
||||||
mac_store_v3s4(r.res, r.dst_ptr, 0),
|
mac_store_v3s4(r.res, r.dst_ptr, 0),
|
||||||
|
|
||||||
jump_reg(R_AtomJmp), BdSlot_ nop // ac_yield: word 3-4
|
jump_reg(R_AtomJmp), BdSlot_ nop // ac_yield: word 3-4
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ enum {
|
|||||||
R_Atom7 = R_T7,
|
R_Atom7 = R_T7,
|
||||||
R_Atom8 = R_T8,
|
R_Atom8 = R_T8,
|
||||||
R_Atom9 = R_T9,
|
R_Atom9 = R_T9,
|
||||||
R_Atom10 = R_V0, // Tend to be used with gte DMAs
|
R_Atom10 = R_V0, // Tend to be used with gte moves
|
||||||
R_Atom11 = R_V1, // Tend to be used with gte DMAs
|
R_Atom11 = R_V1, // Tend to be used with gte moves
|
||||||
R_Atom12 = R_A0,
|
R_Atom12 = R_A0,
|
||||||
R_Atom13 = R_A1,
|
R_Atom13 = R_A1,
|
||||||
R_Atom14 = R_A2,
|
R_Atom14 = R_A2,
|
||||||
@@ -163,6 +163,12 @@ typedef Slice_(MipsAtom);
|
|||||||
// Used for trivial mappings from one atom component proc to the command of a more baser (meant for type-mapping)
|
// Used for trivial mappings from one atom component proc to the command of a more baser (meant for type-mapping)
|
||||||
#define MipsAtomComp_ProcMap_(ab, base_command) atom_dbg_skip MipsAtomComp_Proc_(ab, {base_command })
|
#define MipsAtomComp_ProcMap_(ab, base_command) atom_dbg_skip MipsAtomComp_Proc_(ab, {base_command })
|
||||||
|
|
||||||
|
// WIP: Atoms Assocated closely with each other to form a tape procedure. (Maybe also a phase in a procedure/pipeline?)
|
||||||
|
|
||||||
|
#define AtomBundle_(name) Struct_(tmpl(AtomBundle,name))
|
||||||
|
#define AtomBundle_Len(name) S_(tmpl(AtomBundle,name))/S_(MipsAtom*)
|
||||||
|
#define AtomBundleEntry_(bundle,entry) tmpl(bundle,entry)
|
||||||
|
|
||||||
/* Line-table anchor: gcc only adds a file to the .debug_line file table when the contains line-numbered content.
|
/* Line-table anchor: gcc only adds a file to the .debug_line file table when the contains line-numbered content.
|
||||||
Files containing only atoms and atom components.
|
Files containing only atoms and atom components.
|
||||||
Place `ATOM_FILE_LINE_MARKER();` once at file scope in any `.atom.c` that defines atoms.
|
Place `ATOM_FILE_LINE_MARKER();` once at file scope in any `.atom.c` that defines atoms.
|
||||||
@@ -242,13 +248,17 @@ FI_ TapeBuilder tb_make(Slice mem) { return (TapeBuilder){ u4_(mem.ptr), mem.len
|
|||||||
FI_ void tb_emit(TapeBuilder* tb, MipsAtom* atom) { u4_r(tb->ptr)[tb->used] = u4_(atom); ++ tb->used; }
|
FI_ void tb_emit(TapeBuilder* tb, MipsAtom* 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_ 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)
|
#define tb_emit_(atom) tb_emit(& tb, atom)
|
||||||
#define tb_data_(field, data) tb_data(& tb, u4_(data))
|
|
||||||
|
|
||||||
FI_ void tb_emit_bundle(TapeBuilder_R tb, Slice_MipsAtom atoms) { mem_copy(u4_(tb->ptr), u4_(atoms.ptr), S_slice(atoms)); tb->used += atoms.len; }
|
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_ Tape tb_end (TapeBuilder* tb) { tb_emit(tb,tape_exit); return (Tape){ C_(U4*,tb->ptr), tb->used }; }
|
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 }; }
|
FI_ Tape tb_slice(TapeBuilder tb) { return (Tape){ C_(U4*,tb.ptr), tb.used }; }
|
||||||
#define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,tape_exit))
|
#define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,tape_exit))
|
||||||
|
|
||||||
FI_ void tb_scope_run_end(TapeBuilder* tb) { tb_emit(tb,tape_exit); tape_run(tb_slice(tb[0])); }
|
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))
|
#define tb_scope_run(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_scope_run_end(tb))
|
||||||
@@ -377,10 +387,6 @@ FI_ Reg regfile__alloc_helper(A2_U2 file, Reg r_id) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/* regfile_alloc picks the next free GPR from regfile_alloc_order.
|
|
||||||
* The table is the first-fit allocation order: T0..T7, V0..V1, A0..A3,
|
|
||||||
* S0..S7, T8..T9. The 24 entries leave room for the tape program to use
|
|
||||||
* any of them while R0, R1, R26-R31 remain reserved. */
|
|
||||||
I_ Reg regfile_alloc(RegFile_R rf) {
|
I_ Reg regfile_alloc(RegFile_R rf) {
|
||||||
Reg allocated = 0;
|
Reg allocated = 0;
|
||||||
for index_iter(U4, r_id, R_V0, <, R_T9) {
|
for index_iter(U4, r_id, R_V0, <, R_T9) {
|
||||||
|
|||||||
+2
-9
@@ -4,10 +4,7 @@
|
|||||||
# include "math.h"
|
# include "math.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* PSX button bit positions — 1:1 with PSX-SPX docs at docs/psx-spx/docs/controllersandmemorycards.md:405-421.
|
// PSX button bit positions: PSX-SPX docs/psx-spx/docs/controllersandmemorycards.md:405-421.
|
||||||
* Wire is active-low (0 = pressed).
|
|
||||||
* The decoder atom computes buttons = (~raw_buttons) & 0xFFFF;
|
|
||||||
* active-low-to-active-high inversion is applied bit-by-bit. */
|
|
||||||
typedef Enum_(U2, PadBtns) {
|
typedef Enum_(U2, PadBtns) {
|
||||||
Bit_(Pad_Select, 0),
|
Bit_(Pad_Select, 0),
|
||||||
Bit_(Pad_L3, 1),
|
Bit_(Pad_L3, 1),
|
||||||
@@ -62,11 +59,7 @@ typedef Enum_(U4, PadStatus) {
|
|||||||
PadStatus_Invalid,
|
PadStatus_Invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Distinct from the game-facing PadStatus enum: PadRawStatus_Ok and PadRawStatus_Timeout are raw BIOS values;
|
// Distinct from the game-facing PadStatus enum: PadRawStatus_Ok and PadRawStatus_Timeout are raw BIOS values
|
||||||
* PadStatus_* are game-facing post-decode states. PadUnknownId_Sentinel is written by the decoder
|
|
||||||
* when the controller id does not match any known controller type.
|
|
||||||
* PadAxisCentered_Word: Four-byte 0x80 pattern used to clear / center
|
|
||||||
* four byte axes at PadState.left_x through PadState.right_y. */
|
|
||||||
typedef Enum_(U1, PadRawStatus) {
|
typedef Enum_(U1, PadRawStatus) {
|
||||||
PadRawStatus_Ok = 0x00,
|
PadRawStatus_Ok = 0x00,
|
||||||
PadRawStatus_Timeout = 0xFF,
|
PadRawStatus_Timeout = 0xFF,
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ void gte_matrix_set_translation(MT3_S2S4* mat) asm("SetTransMatrix");
|
|||||||
|
|
||||||
// Einheit, Metrication to unit vector. "Normalization", not Orthogonal "Normal, Normalis". Directionalization.
|
// Einheit, Metrication to unit vector. "Normalization", not Orthogonal "Normal, Normalis". Directionalization.
|
||||||
// RGA(Lengyel): Normalize the bulk of a zero-weight direction. This is not finite-point unitization (which forces w=1).
|
// RGA(Lengyel): Normalize the bulk of a zero-weight direction. This is not finite-point unitization (which forces w=1).
|
||||||
S4 normalize_v3s4(V3_S4* v0, V3_S4* v1) asm("VectorNormal");
|
S4 psy_normalize_v3s4(V3_S4* v0, V3_S4* v1) asm("VectorNormal");
|
||||||
|
|
||||||
// RGA(Lengyel): Apply the matrix expansion of a rigid transformation.
|
// RGA(Lengyel): Apply the matrix expansion of a rigid transformation.
|
||||||
// Motor antiproduct is equivalent for unitized points; LA form is what GTE consumes.
|
// Motor antiproduct is equivalent for unitized points; LA form is what GTE consumes.
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
|
|||||||
load_word(r.target_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,target)),
|
load_word(r.target_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,target)),
|
||||||
load_word(r.eye_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)),
|
load_word(r.eye_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)),
|
||||||
load_word(r.up_in_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)),
|
load_word(r.up_in_ptr, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)),
|
||||||
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtSub)),
|
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtSub)),
|
||||||
|
|
||||||
/* Stage up_in.x/y/z into the scratchpad. R_ScratchBase = R_SP = 0x1F800000. */
|
/* Stage up_in.x/y/z into the scratchpad. R_ScratchBase = R_SP = 0x1F800000. */
|
||||||
mac_load_v3s4( r.up_in, r.up_in_ptr, 0), LdSlot_
|
mac_load_v3s4( r.up_in, r.up_in_ptr, 0), LdSlot_
|
||||||
@@ -155,7 +155,7 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
typedef Struct_(Binds_ResolveLookAt_PopulateMT3S4S2) {
|
typedef Struct_(Binds_ResolveLookAt_PopulateMT3S4S2) {
|
||||||
U4 look_at; /* MT3_S2S4* — destination matrix address */
|
MT3_S2S4* look_at; /* MT3_S2S4* — destination matrix address */
|
||||||
};
|
};
|
||||||
typedef Struct_(RegUse_resolve_look_at_populate_mt3s4s2) {
|
typedef Struct_(RegUse_resolve_look_at_populate_mt3s4s2) {
|
||||||
Reg look_at;
|
Reg look_at;
|
||||||
@@ -182,7 +182,7 @@ internal MipsAtom* AtomBundleEntry_(resolve_look_at,populate_mt3s4s2)(AtomArena_
|
|||||||
atom_info(atom_bind(Binds_ResolveLookAt_PopulateMT3S4S2)) MipsAtom_Proc_(aa, {
|
atom_info(atom_bind(Binds_ResolveLookAt_PopulateMT3S4S2)) MipsAtom_Proc_(aa, {
|
||||||
/* --- Tape pop: look_at pointer --- */
|
/* --- Tape pop: look_at pointer --- */
|
||||||
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAt_PopulateMT3S4S2,look_at)),
|
load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAt_PopulateMT3S4S2,look_at)),
|
||||||
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAt_PopulateMT3S4S2)),
|
LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAt_PopulateMT3S4S2)),
|
||||||
|
|
||||||
add_si(r.ux, R_ScratchBase, O_(ResolveLookAtScratch, ux)), LdSlot_
|
add_si(r.ux, R_ScratchBase, O_(ResolveLookAtScratch, ux)), LdSlot_
|
||||||
add_si(r.uy, R_ScratchBase, O_(ResolveLookAtScratch, uy)),
|
add_si(r.uy, R_ScratchBase, O_(ResolveLookAtScratch, uy)),
|
||||||
@@ -288,23 +288,6 @@ internal MipsAtom_(screen_env_init) atom_info(atom_phase(screen_init)
|
|||||||
mac_yield(),
|
mac_yield(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* gp_screen_init's GPR setup. Tests the mixed user-pinning + auto-reg pattern:
|
|
||||||
* - R_IO_BaseAddr = R_T4 (user-pinned via atom_reg; pre-existing)
|
|
||||||
* - R_GP1_Offset = R_T2 (user-pinned via atom_reg; NEW -- for GPIO_PORT1_OFFSET)
|
|
||||||
* - R_ScreenX = R_T5 (user-pinned via atom_reg; used as a transfer and GTE setup reg)
|
|
||||||
* - R_GpTmp = auto-allocated by the lua pass and used for several GPU transfers;
|
|
||||||
* the C preprocessor resolves it to the chosen free pool GPR.
|
|
||||||
*
|
|
||||||
* For gp_screen_init, the auto-reg pool exclusions are:
|
|
||||||
* user_pinned (from the corpus register_alias_registry) : R_T0..R_T7 (all 8 user-pinned across hello_camera.atom.c)
|
|
||||||
* body-parsed physical registers : aliases resolve through the registry;
|
|
||||||
* the body uses R_ScreenX, not raw R_T5
|
|
||||||
* source_pool after both subtractions : {R_V0, R_V1} only
|
|
||||||
* R_GpTmp gets R_V0 (the first-fit choice). Its repeated GPU-transfer use proves that the
|
|
||||||
* auto-reg allocation is active while the R_ScreenX references prove the pinned alias is used.
|
|
||||||
* R_TapePtr (R_T9), R_AtomJmp (R_T8), R_AT are excluded from the POOL by construction in
|
|
||||||
* passes/auto_reg.lua -- see the "obvious exclusions" comment block at the top of that file.
|
|
||||||
*/
|
|
||||||
enum {
|
enum {
|
||||||
R_IO_BaseAddr = R_T4 atom_reg, /* Caller-pinned: IO_BASE_ADDR = 0x1F800000 */
|
R_IO_BaseAddr = R_T4 atom_reg, /* Caller-pinned: IO_BASE_ADDR = 0x1F800000 */
|
||||||
R_GP1_Offset = R_T2 atom_reg, /* Caller-pinned: GPIO_PORT1_OFFSET = 0x10 */
|
R_GP1_Offset = R_T2 atom_reg, /* Caller-pinned: GPIO_PORT1_OFFSET = 0x10 */
|
||||||
@@ -545,11 +528,13 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
|
|||||||
load_half_u(R_T2, R_FaceCursor, 2 * S_(S2)),
|
load_half_u(R_T2, R_FaceCursor, 2 * S_(S2)),
|
||||||
// load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)),
|
// load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)),
|
||||||
|
|
||||||
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_
|
LdSlot_ mac_gte_load_tri_verts(R_VertBase, R_T0, R_T1, R_T2),
|
||||||
GteDelay_ nop, gte_cmdw_rotate_translate_perspective_triple,
|
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,
|
||||||
|
gte_cmdw_rotate_translate_perspective_triple,
|
||||||
gte_cmdw_nclip,
|
gte_cmdw_nclip,
|
||||||
|
|
||||||
gte_mv_from_data_r(R_T0, C2_MAC0), GteDelay_ load_word(R_AtomJmp, R_TapePtr, 0), // ac_yield: word 1
|
gte_mv_from_data_r(R_T0, C2_MAC0), GteDelay_ add_ui_self(R_TapePtr, S_(MipsCode)), // ac_yield: word 1
|
||||||
branch_le_zero(R_T0, atom_offset(cull, cube_g4_face_exit)),
|
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).
|
/* 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 —
|
* If branch IS taken (face culled), the body is skipped and this 0-tag is stranded —
|
||||||
@@ -568,7 +553,7 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
|
|||||||
add_ui( R_AT, R_0, OrderingTbl_Len),
|
add_ui( R_AT, R_0, OrderingTbl_Len),
|
||||||
set_lt_u( R_AT, R_T1, R_AT),
|
set_lt_u( R_AT, R_T1, R_AT),
|
||||||
|
|
||||||
branch_equal(R_AT, R_0, atom_offset(bounds_chk, cube_g4_face_exit)), BdSlot_ add_ui_self(R_TapePtr, S_(MipsCode)), // ac_yield: word 2
|
branch_equal(R_AT, R_0, atom_offset(bounds_chk, cube_g4_face_exit)), BdSlot_ nop,
|
||||||
mac_insert_ot_tag(R_OtBase, R_PrimCursor, S_(Poly_G4)),
|
mac_insert_ot_tag(R_OtBase, R_PrimCursor, S_(Poly_G4)),
|
||||||
mac_format_g4_color(R_PrimCursor,
|
mac_format_g4_color(R_PrimCursor,
|
||||||
/* c0 magenta */ 0xFF, 0x00, 0xFF,
|
/* c0 magenta */ 0xFF, 0x00, 0xFF,
|
||||||
@@ -581,7 +566,7 @@ MipsAtom_(cube_g4_face) atom_info(atom_phase(cube_g4),
|
|||||||
atom_label(cube_g4_face_exit)
|
atom_label(cube_g4_face_exit)
|
||||||
add_ui_self(R_PrimCursor, S_(Poly_G4)), /* 9 words = Poly_G4 */
|
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_FaceCursor, S_(S2) * 4), /* 4 × S2 = 8 bytes */
|
||||||
jump_reg(R_TapePtr), BdSlot_ nop // ac_yield: word 3-4
|
jump_reg(R_AtomJmp), BdSlot_ nop // ac_yield: word 3-4
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Struct_(Binds_FloorTri) {
|
typedef Struct_(Binds_FloorTri) {
|
||||||
@@ -638,7 +623,7 @@ MipsAtom_(floor_f3_face) atom_info(atom_phase(floor_f3)
|
|||||||
/* Advance Input Cursor & Yield (Both branch targets land here) */
|
/* Advance Input Cursor & Yield (Both branch targets land here) */
|
||||||
atom_label(floor_f3_face_exit)
|
atom_label(floor_f3_face_exit)
|
||||||
add_ui_self(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
add_ui_self(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
||||||
jump_reg(R_TapePtr), BdSlot_ nop // ac_yield: word 3-4
|
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; U4 cursor; };
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ typedef Struct_(SMemory) {
|
|||||||
PadBiosRaw pad_raw[2];
|
PadBiosRaw pad_raw[2];
|
||||||
PadState pad[2];
|
PadState pad[2];
|
||||||
|
|
||||||
// TODO(Ed): We don't need this we can just cast at any point an address to a desired view of scratchpad, we have the address.
|
|
||||||
U4_V scratchpad; // d-cache
|
|
||||||
|
|
||||||
U1 ct_init_atom_mem[CT_InitAtomMem_Size];
|
U1 ct_init_atom_mem[CT_InitAtomMem_Size];
|
||||||
MipsAtom* normalize_v3s4;
|
MipsAtom* normalize_v3s4;
|
||||||
MipsAtom* gte_cross_v3s4;
|
MipsAtom* gte_cross_v3s4;
|
||||||
@@ -114,10 +111,10 @@ I_ void resolve_look_at_c11(MT3_S2S4* look_at, P3_S4* eye, P3_S4* target, V3_S4*
|
|||||||
V3_S4 pos, off;
|
V3_S4 pos, off;
|
||||||
|
|
||||||
forward = target[0]; sub_v3s4(& forward, eye[0]); // RGA(Lengyel): Affine point - point = zero-weight direction.
|
forward = target[0]; sub_v3s4(& forward, eye[0]); // RGA(Lengyel): Affine point - point = zero-weight direction.
|
||||||
normalize_v3s4(& forward, & uz); // RGA(Lengyel): Normalize the direction bulk. Not finite-point unitization.
|
psy_normalize_v3s4(& forward, & uz); // RGA(Lengyel): Normalize the direction bulk. Not finite-point unitization.
|
||||||
|
|
||||||
cross_v3s4(& uz, up_in, & right); normalize_v3s4(& right, & ux); // RGA(Lengyel): Complement(Wedge(forward, up_in)) -> right axis.
|
cross_v3s4(& uz, up_in, & right); psy_normalize_v3s4(& right, & ux); // RGA(Lengyel): Complement(Wedge(forward, up_in)) -> right axis.
|
||||||
cross_v3s4(& uz, & ux, & up); normalize_v3s4(& up, & uy); // RGA(Lengyel): Complement(Wedge(forward, right)) -> up axis.
|
cross_v3s4(& uz, & ux, & up); psy_normalize_v3s4(& up, & uy); // RGA(Lengyel): Complement(Wedge(forward, right)) -> up axis.
|
||||||
|
|
||||||
// RGA(Lengyel): matrix expansion of the world-to-camera rotation (basis rows).
|
// RGA(Lengyel): matrix expansion of the world-to-camera rotation (basis rows).
|
||||||
look_at->m[0][0] = ux.x; look_at->m[0][1] = ux.y; look_at->m[0][2] = ux.z;
|
look_at->m[0][0] = ux.x; look_at->m[0][1] = ux.y; look_at->m[0][2] = ux.z;
|
||||||
@@ -149,8 +146,8 @@ internal void compile_init_atoms(void) {
|
|||||||
});
|
});
|
||||||
regfile_reset(& rf);
|
regfile_reset(& rf);
|
||||||
|
|
||||||
smem.normalize_v3s4 = build_normalize_v3s4(& ab,
|
smem.normalize_v3s4 = normalize_v3s4(& ab,
|
||||||
RegUse_(build_normalize_v3s4) {
|
RegUse_(normalize_v3s4) {
|
||||||
.res = ralloc_v3(),
|
.res = ralloc_v3(),
|
||||||
.r0 = ralloc(),
|
.r0 = ralloc(),
|
||||||
.r1 = ralloc(),
|
.r1 = ralloc(),
|
||||||
@@ -167,15 +164,11 @@ internal void compile_init_atoms(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void compile_resolve_look_at(void) {
|
internal void compile_resolve_look_at(void) {
|
||||||
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
|
|
||||||
AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
|
AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
|
||||||
|
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
|
||||||
/* R_ScratchBase (= R_SP) is a tape carrier preserved across atoms; no carrier
|
RegFile rf = regfile(regfile_abi_mask);
|
||||||
* pin is needed in the regfile. The standard 24-register pool is sufficient. */
|
|
||||||
RegFile rf = regfile(regfile_abi_mask);
|
|
||||||
#define ralloc() regfile_alloc(& rf)
|
#define ralloc() regfile_alloc(& rf)
|
||||||
#define ralloc_v3() { ralloc(), ralloc(), ralloc() }
|
#define ralloc_v3() { ralloc(), ralloc(), ralloc() }
|
||||||
|
|
||||||
bundle->input_and_sub = AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab,
|
bundle->input_and_sub = AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab,
|
||||||
RegUse_(resolve_look_at_input_and_sub) {
|
RegUse_(resolve_look_at_input_and_sub) {
|
||||||
.target_ptr = ralloc(),
|
.target_ptr = ralloc(),
|
||||||
@@ -203,52 +196,48 @@ internal void compile_resolve_look_at(void) {
|
|||||||
.r2 = ralloc(),
|
.r2 = ralloc(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Sanity check: arena didn't overflow. */
|
assert(ab.used <= ResolveLookAtArena_Size); // Sanity check: arena didn't overflow.
|
||||||
assert(ab.used <= ResolveLookAtArena_Size);
|
|
||||||
#undef ralloc
|
#undef ralloc
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Emit the resolve_look_at bundle into the tape. Called once per frame from update(). */
|
// Emit the resolve_look_at bundle into the tape. Called once per frame from update().
|
||||||
I_ void resolve_look_at(TapeBuilder_R tb
|
I_ void resolve_look_at(TapeBuilder_R tb, MT3_S2S4* look_at, P3_S4* eye, P3_S4* target, V3_S4* up_in) {
|
||||||
, MT3_S2S4* look_at
|
|
||||||
, P3_S4* eye
|
|
||||||
, P3_S4* target
|
|
||||||
, V3_S4* up_in
|
|
||||||
){
|
|
||||||
/* Typed view of the scratchpad for field-address arithmetic. */
|
/* Typed view of the scratchpad for field-address arithmetic. */
|
||||||
ResolveLookAtScratch* sp = C_scratch(ResolveLookAtScratch*);
|
ResolveLookAtScratch* sp = C_scratch(ResolveLookAtScratch*);
|
||||||
AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
|
AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
|
||||||
|
tb_emit(tb, bundle->input_and_sub); tb_bind_(tb, Binds_ResolveLookAtSub,
|
||||||
tb_emit(tb, bundle->input_and_sub); {
|
.target = target,
|
||||||
tb_data(tb, u4_(target));
|
.eye = eye,
|
||||||
tb_data(tb, u4_(eye));
|
.up_in = up_in,
|
||||||
tb_data(tb, u4_(up_in));
|
);
|
||||||
}
|
tb_emit(tb, bundle->normalize_fwd_uz); tb_bind_(tb, Binds_normalize_v3s4,
|
||||||
tb_emit(tb, bundle->normalize_fwd_uz); {
|
.src_offset = O_(ResolveLookAtScratch,fwd),
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16)));
|
.dst_offset = O_(ResolveLookAtScratch,uz),
|
||||||
}
|
);
|
||||||
tb_emit(tb, bundle->cross_to_right); {
|
tb_emit(tb, bundle->cross_to_right); tb_bind_(tb, Binds_gte_cross_v3s4,
|
||||||
tb_data(tb, u4_(& sp->uz));
|
.src_a = & sp->uz,
|
||||||
tb_data(tb, u4_(& sp->up_in));
|
.src_b = & sp->up_in,
|
||||||
tb_data(tb, u4_(& sp->right));
|
.out = & sp->right,
|
||||||
}
|
);
|
||||||
tb_emit(tb, bundle->normalize_right_ux); {
|
tb_emit(tb, bundle->normalize_right_ux); tb_bind_(tb, Binds_normalize_v3s4,
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, right) | (O_(ResolveLookAtScratch, ux) << 16)));
|
.src_offset = O_(ResolveLookAtScratch,right),
|
||||||
}
|
.dst_offset = O_(ResolveLookAtScratch,ux),
|
||||||
tb_emit(tb, bundle->cross_to_up); {
|
);
|
||||||
tb_data(tb, u4_(& sp->uz));
|
tb_emit(tb, bundle->cross_to_up); tb_bind_(tb, Binds_gte_cross_v3s4,
|
||||||
tb_data(tb, u4_(& sp->ux));
|
.src_a = & sp->uz,
|
||||||
tb_data(tb, u4_(& sp->up));
|
.src_b = & sp->ux,
|
||||||
}
|
.out = & sp->up,
|
||||||
tb_emit(tb, bundle->normalize_up_uy); {
|
);
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, up) | (O_(ResolveLookAtScratch, uy) << 16)));
|
tb_emit(tb, bundle->normalize_up_uy); tb_bind_(tb, Binds_normalize_v3s4,
|
||||||
}
|
.src_offset = O_(ResolveLookAtScratch,up),
|
||||||
tb_emit(tb, bundle->populate_mt3s4s2); {
|
.dst_offset = O_(ResolveLookAtScratch,uy),
|
||||||
tb_data(tb, u4_(look_at));
|
);
|
||||||
}
|
tb_emit(tb, bundle->populate_mt3s4s2); tb_bind_(tb, Binds_ResolveLookAt_PopulateMT3S4S2,
|
||||||
|
.look_at = look_at,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
FI_ void camera_look_at(TapeBuilder_R tb, Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at(tb, & c->look_at, & c->pos, target, up_in); }
|
||||||
|
|
||||||
GCC_OPTIMIZATION_DISABLE
|
|
||||||
void update(PrimitiveArena* pa, U4* ordering_buf)
|
void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||||
{
|
{
|
||||||
TapeBuilder tb = tb_make(slice_ut_arr(smem.MemTape));
|
TapeBuilder tb = tb_make(slice_ut_arr(smem.MemTape));
|
||||||
@@ -258,15 +247,15 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
tb.used = 0; tb_scope_run(& tb) {
|
tb.used = 0; tb_scope_run(& tb) {
|
||||||
// Grab latest state from bios.
|
// Grab latest state from bios.
|
||||||
tb_emit_(pad_bios_snapshot);
|
tb_emit_(pad_bios_snapshot);
|
||||||
tb_data_(raw, & smem.pad_raw[0]);
|
tb_data(& tb, u4_(& smem.pad_raw[0]));
|
||||||
tb_data_(state, & smem.pad[0]);
|
tb_data(& tb, u4_(& smem.pad[0]));
|
||||||
// tb_emit_(pad_bios_snapshot);
|
// tb_emit_(pad_bios_snapshot);
|
||||||
// tb_data_(raw, & smem.pad_raw[1]);
|
// tb_data_(raw, & smem.pad_raw[1]);
|
||||||
// tb_data_(state, & smem.pad[1]);
|
// tb_data_(state, & smem.pad[1]);
|
||||||
|
|
||||||
tb_emit_(pad_input_cam);
|
tb_emit_(pad_input_cam);
|
||||||
tb_data_(state, & smem.pad[0]);
|
tb_data(& tb, u4_(& smem.pad[0]));
|
||||||
tb_data_(cam, & smem.cam);
|
tb_data(& tb, u4_(& smem.cam));
|
||||||
|
|
||||||
// tb_emit_(pad_input_cube_rotation);
|
// tb_emit_(pad_input_cube_rotation);
|
||||||
// tb_data_(state, & smem.pad[0]);
|
// tb_data_(state, & smem.pad[0]);
|
||||||
@@ -299,7 +288,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
if (use_c11_path == false)
|
if (use_c11_path == false)
|
||||||
{
|
{
|
||||||
tb.used = 0; tb_scope_run(& tb) {
|
tb.used = 0; tb_scope_run(& tb) {
|
||||||
resolve_look_at(& tb, & smem.cam.look_at, & smem.cam.pos, & smem.cube.pos, & v3s4(0, -fp_one, 0));
|
camera_look_at(& tb, & smem.cam, & smem.cube.pos, & v3s4(0, -fp_one, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +371,6 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
// smem.floor.rot.y += 5;
|
// smem.floor.rot.y += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GCC_OPTIMIZATION_ENABLE
|
|
||||||
|
|
||||||
void render(void) {
|
void render(void) {
|
||||||
}
|
}
|
||||||
@@ -399,12 +387,9 @@ void gp_display_frame(DoubleBuffer* screen_buf, S4* active_buf_id, U4* ordering_
|
|||||||
active_buf_id[0] = ! active_buf_id[0]; // Swap current buffer
|
active_buf_id[0] = ! active_buf_id[0]; // Swap current buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
GCC_OPTIMIZATION_DISABLE
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
smem = (SMemory){0};
|
smem = (SMemory){0};
|
||||||
// TODO(Ed): remove this field we don't need it in smem.
|
|
||||||
smem.scratchpad = C_(U4_V, Scratchpad_Loc);
|
|
||||||
// smem.primitives.used = 0;
|
// smem.primitives.used = 0;
|
||||||
// smem.active_buf_id = 0;
|
// smem.active_buf_id = 0;
|
||||||
smem.cam.pos = v3s4(500, -1000, -1500);
|
smem.cam.pos = v3s4(500, -1000, -1500);
|
||||||
@@ -449,4 +434,3 @@ int main(void)
|
|||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
GCC_OPTIMIZATION_ENABLE
|
|
||||||
|
|||||||
@@ -1041,6 +1041,16 @@ function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len)
|
|||||||
if source:sub(next_pos, next_pos) == "(" then
|
if source:sub(next_pos, next_pos) == "(" then
|
||||||
local inner, after_paren = M.read_parens(source, next_pos) ---@type string|nil, integer
|
local inner, after_paren = M.read_parens(source, next_pos) ---@type string|nil, integer
|
||||||
if inner then
|
if inner then
|
||||||
|
if ident == "AtomBundleEntry_" then
|
||||||
|
local tmpl = M.split_top_level_commas(inner) ---@type string[]
|
||||||
|
if #tmpl ~= 2 then return nil end
|
||||||
|
local name = M.trim(tmpl[1]) .. "_" .. M.trim(tmpl[2]) ---@type string
|
||||||
|
local formals_pos = M.skip_ws_and_cmt(source, after_paren) ---@type integer
|
||||||
|
if source:sub(formals_pos, formals_pos) ~= "(" then return nil end
|
||||||
|
local real_inner, after_real = M.read_parens(source, formals_pos) ---@type string|nil, integer
|
||||||
|
if not real_inner then return nil end
|
||||||
|
return name, real_inner, name, after_real
|
||||||
|
end
|
||||||
return ident, inner, ident, after_paren
|
return ident, inner, ident, after_paren
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -544,6 +544,50 @@ local function render_section_binds(add, view)
|
|||||||
if not wrote then add("_(none)_"); add("") end
|
if not wrote then add("_(none)_"); add("") end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param add fun(s: string): nil
|
||||||
|
--- @param view ModuleView
|
||||||
|
--- @return nil
|
||||||
|
local function render_section_atom_bundles(add, view)
|
||||||
|
local bundles = (view.corpus and view.corpus.atom_bundles) or {} ---@type table<string, AtomBundle>
|
||||||
|
local names = {} ---@type string[]
|
||||||
|
for name, bundle in pairs(bundles) do ---@type string, AtomBundle
|
||||||
|
if path_in_module(bundle.path, view) then
|
||||||
|
names[#names + 1] = name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #names == 0 then add("_(none)_"); add(""); return end
|
||||||
|
table.sort(names)
|
||||||
|
for _, name in ipairs(names) do ---@type integer, string
|
||||||
|
local bundle = bundles[name] ---@type AtomBundle
|
||||||
|
local entries = bundle.entries or {} ---@type table<string, string>
|
||||||
|
add(string.format("### %s", name))
|
||||||
|
for _, slot in ipairs(bundle.slots or {}) do ---@type integer, string
|
||||||
|
local ident = entries[slot] ---@type string|nil
|
||||||
|
if ident then
|
||||||
|
add(string.format("- `%s` `%s`", slot, ident))
|
||||||
|
else
|
||||||
|
add(string.format("- `%s`", slot))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
add("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param add fun(s: string): nil
|
||||||
|
--- @param view ModuleView
|
||||||
|
--- @return nil
|
||||||
|
local function render_section_tape_emits(add, view)
|
||||||
|
local wrote = false ---@type boolean
|
||||||
|
for _, src in ipairs(view.sources or {}) do ---@type integer, SourceFile
|
||||||
|
for _, emit in ipairs((src.scan and src.scan.tape_emits) or {}) do ---@type integer, TapeEmit
|
||||||
|
wrote = true
|
||||||
|
add(string.format("- `%s` `%s`", emit.name or "?", emit.binds or "—"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not wrote then add("_(none)_"); add(""); return end
|
||||||
|
add("")
|
||||||
|
end
|
||||||
|
|
||||||
--- @param add fun(s: string): nil
|
--- @param add fun(s: string): nil
|
||||||
--- @param view ModuleView
|
--- @param view ModuleView
|
||||||
--- @return nil
|
--- @return nil
|
||||||
@@ -895,6 +939,8 @@ local SECTION_RENDERERS = { ---@type SectionRenderer[]
|
|||||||
{ header = "## Annotations", render = render_section_annotations },
|
{ header = "## Annotations", render = render_section_annotations },
|
||||||
{ header = "## Component annotations", render = render_section_component_annotations },
|
{ header = "## Component annotations", render = render_section_component_annotations },
|
||||||
{ header = "## Binds_* structs", render = render_section_binds },
|
{ header = "## Binds_* structs", render = render_section_binds },
|
||||||
|
{ header = "## Atom bundles", render = render_section_atom_bundles },
|
||||||
|
{ header = "## Tape emits", render = render_section_tape_emits },
|
||||||
{ header = "## Phases / views / ctx", render = render_section_phases },
|
{ header = "## Phases / views / ctx", render = render_section_phases },
|
||||||
{ header = "## Register aliases", render = render_section_aliases },
|
{ header = "## Register aliases", render = render_section_aliases },
|
||||||
{ header = "## Auto-reg", render = render_section_autoreg },
|
{ header = "## Auto-reg", render = render_section_autoreg },
|
||||||
|
|||||||
@@ -127,6 +127,13 @@ local parse_enum_int_literal ---@type fun(text: string, start: integer): (intege
|
|||||||
--- @field body string
|
--- @field body string
|
||||||
--- @field bytes integer|nil
|
--- @field bytes integer|nil
|
||||||
|
|
||||||
|
--- @class AtomBundle
|
||||||
|
--- @field name string
|
||||||
|
--- @field slots string[] -- typedef order
|
||||||
|
--- @field line integer
|
||||||
|
--- @field path string
|
||||||
|
--- @field entries table<string, string>|nil -- slot → B_E when an AtomBundleEntry_ proc exists
|
||||||
|
|
||||||
--- @class AliasEntry
|
--- @class AliasEntry
|
||||||
--- @field name string
|
--- @field name string
|
||||||
--- @field code integer
|
--- @field code integer
|
||||||
@@ -182,6 +189,14 @@ local parse_enum_int_literal ---@type fun(text: string, start: integer): (intege
|
|||||||
--- @class TapeChain
|
--- @class TapeChain
|
||||||
--- @field [integer] string -- ordered atom names in one tb_emit chain
|
--- @field [integer] string -- ordered atom names in one tb_emit chain
|
||||||
|
|
||||||
|
--- @class TapeEmit
|
||||||
|
--- @field name string
|
||||||
|
--- @field binds string|nil
|
||||||
|
--- @field line integer
|
||||||
|
--- @field path string
|
||||||
|
--- @field slot string|nil
|
||||||
|
--- @field data_words integer|nil
|
||||||
|
|
||||||
--- @class RegUseView
|
--- @class RegUseView
|
||||||
--- @field names string[]
|
--- @field names string[]
|
||||||
--- @field lanes boolean
|
--- @field lanes boolean
|
||||||
@@ -208,6 +223,8 @@ local parse_enum_int_literal ---@type fun(text: string, start: integer): (intege
|
|||||||
--- @field reg_use_schemas table<string, RegUseSchema>
|
--- @field reg_use_schemas table<string, RegUseSchema>
|
||||||
--- @field reg_use_errors RegUseError[]
|
--- @field reg_use_errors RegUseError[]
|
||||||
--- @field tape_chains TapeChain[]
|
--- @field tape_chains TapeChain[]
|
||||||
|
--- @field tape_emits TapeEmit[]
|
||||||
|
--- @field atom_bundles table<string, AtomBundle>
|
||||||
--- @field _source_file string|nil
|
--- @field _source_file string|nil
|
||||||
--- @field _code_macros table<string, integer>|nil -- bag
|
--- @field _code_macros table<string, integer>|nil -- bag
|
||||||
--- @field _code_macro_bodies table<string, string>|nil -- bag
|
--- @field _code_macro_bodies table<string, string>|nil -- bag
|
||||||
@@ -2439,11 +2456,76 @@ local function parse_typedef_array(source, pos, id2_end, line_of, out, after_typ
|
|||||||
return semi and (semi + 1) or after_paren
|
return semi and (semi + 1) or after_paren
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Parse `MipsAtom *slot, …;` from an AtomBundle_ typedef body.
|
||||||
|
--- Ignores the MipsAtom type token. Slot name is the ident after `*`.
|
||||||
|
--- @param body string
|
||||||
|
--- @return string[]
|
||||||
|
local function parse_atom_bundle_slots(body)
|
||||||
|
local slots = {} ---@type string[]
|
||||||
|
local pos = 1 ---@type integer
|
||||||
|
while pos <= #body do
|
||||||
|
pos = duffle.skip_ws_and_cmt(body, pos)
|
||||||
|
if pos > #body then break end
|
||||||
|
local b = body:byte(pos) ---@type integer
|
||||||
|
if b == BYTE_SEMI then
|
||||||
|
break
|
||||||
|
elseif b == BYTE_COMMA then
|
||||||
|
pos = pos + 1
|
||||||
|
elseif b == BYTE_STAR then
|
||||||
|
local after_star = duffle.skip_ws_and_cmt(body, pos + 1) ---@type integer
|
||||||
|
local ident, ident_end = duffle.read_ident(body, after_star) ---@type string|nil, integer
|
||||||
|
if ident then
|
||||||
|
slots[#slots + 1] = ident
|
||||||
|
pos = ident_end
|
||||||
|
else
|
||||||
|
pos = pos + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local ident, ident_end = duffle.read_ident(body, pos) ---@type string|nil, integer
|
||||||
|
if ident then
|
||||||
|
pos = ident_end
|
||||||
|
else
|
||||||
|
pos = pos + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return slots
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Shape 5: `typedef AtomBundle_(<name>) { MipsAtom *slot, … };`
|
||||||
|
--- @param source string
|
||||||
|
--- @param pos integer
|
||||||
|
--- @param id2_end integer
|
||||||
|
--- @param line_of fun(pos: integer): integer
|
||||||
|
--- @param out SourceScan
|
||||||
|
--- @param after_typedef integer
|
||||||
|
--- @return integer
|
||||||
|
local function parse_typedef_atom_bundle(source, pos, id2_end, line_of, out, after_typedef)
|
||||||
|
local inner, after_paren, open_paren = read_parens_after(source, id2_end, id2_end) ---@type string|nil, integer, integer
|
||||||
|
if not inner then return id2_end end
|
||||||
|
local name = duffle.trim(inner) ---@type string
|
||||||
|
|
||||||
|
local body, after_brace = find_body_braces(source, after_paren, open_paren + 1) ---@type string|nil, integer
|
||||||
|
if not body then return after_brace end
|
||||||
|
if name ~= "" and out.atom_bundles[name] == nil then
|
||||||
|
local bundle = { ---@type AtomBundle
|
||||||
|
name = name,
|
||||||
|
slots = parse_atom_bundle_slots(body),
|
||||||
|
line = line_of(pos),
|
||||||
|
path = out._source_file or "",
|
||||||
|
}
|
||||||
|
out.atom_bundles[name] = bundle
|
||||||
|
end
|
||||||
|
attach_debug_skip_marker(out, "unrelated")
|
||||||
|
return after_brace
|
||||||
|
end
|
||||||
|
|
||||||
local TYPE_FORMS = { ---@type table<string, fun(source: string, pos: integer, id2_end: integer, line_of: fun(pos: integer): integer, out: SourceScan, after_typedef: integer): integer>
|
local TYPE_FORMS = { ---@type table<string, fun(source: string, pos: integer, id2_end: integer, line_of: fun(pos: integer): integer, out: SourceScan, after_typedef: integer): integer>
|
||||||
Struct_ = parse_typedef_struct,
|
Struct_ = parse_typedef_struct,
|
||||||
Enum_ = parse_typedef_enum,
|
Enum_ = parse_typedef_enum,
|
||||||
TSet_ = parse_typedef_tset,
|
TSet_ = parse_typedef_tset,
|
||||||
Array_ = parse_typedef_array,
|
Array_ = parse_typedef_array,
|
||||||
|
AtomBundle_ = parse_typedef_atom_bundle,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Parse: `typedef` declarations.
|
--- Parse: `typedef` declarations.
|
||||||
@@ -2827,6 +2909,23 @@ local function parse_addrs_assign(source, pos, ident_end, line_of, out)
|
|||||||
return rhs
|
return rhs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param out SourceScan
|
||||||
|
--- @param name string
|
||||||
|
--- @param last string
|
||||||
|
--- @param line integer
|
||||||
|
--- @return nil
|
||||||
|
local function push_tape_emit(out, name, last, line)
|
||||||
|
out.tape_emits = out.tape_emits or {}
|
||||||
|
out.tape_emits[#out.tape_emits + 1] = { ---@type TapeEmit
|
||||||
|
name = name,
|
||||||
|
binds = nil,
|
||||||
|
line = line,
|
||||||
|
path = out._source_file or "",
|
||||||
|
slot = last:find("->", 1, true) and name or nil,
|
||||||
|
data_words = 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
--- @param source string
|
--- @param source string
|
||||||
--- @param pos integer
|
--- @param pos integer
|
||||||
--- @param ident_end integer
|
--- @param ident_end integer
|
||||||
@@ -2837,10 +2936,12 @@ local function parse_tb_emit_(source, pos, ident_end, line_of, out)
|
|||||||
local after = duffle.skip_ws_and_cmt(source, ident_end) ---@type integer
|
local after = duffle.skip_ws_and_cmt(source, ident_end) ---@type integer
|
||||||
if source:sub(after, after) ~= "(" then return ident_end end
|
if source:sub(after, after) ~= "(" then return ident_end end
|
||||||
local inner, after_p = duffle.read_parens(source, after) ---@type string|nil, integer
|
local inner, after_p = duffle.read_parens(source, after) ---@type string|nil, integer
|
||||||
local name = duffle.trim(inner or ""):match("^([%w_]+)") ---@type string
|
local last = duffle.trim(inner or "") ---@type string
|
||||||
|
local name = last:match("^([%w_]+)") ---@type string
|
||||||
if name then
|
if name then
|
||||||
out._chain = out._chain or {}
|
out._chain = out._chain or {}
|
||||||
out._chain[#out._chain + 1] = name
|
out._chain[#out._chain + 1] = name
|
||||||
|
push_tape_emit(out, name, last, line_of(pos))
|
||||||
end
|
end
|
||||||
return after_p or (after + 1)
|
return after_p or (after + 1)
|
||||||
end
|
end
|
||||||
@@ -2865,6 +2966,49 @@ local function parse_tb_emit(source, pos, ident_end, line_of, out)
|
|||||||
if name then
|
if name then
|
||||||
out._chain = out._chain or {}
|
out._chain = out._chain or {}
|
||||||
out._chain[#out._chain + 1] = name
|
out._chain[#out._chain + 1] = name
|
||||||
|
push_tape_emit(out, name, last, line_of(pos))
|
||||||
|
end
|
||||||
|
return after_p or (after + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param source string
|
||||||
|
--- @param pos integer
|
||||||
|
--- @param ident_end integer
|
||||||
|
--- @param line_of fun(pos: integer): integer
|
||||||
|
--- @param out SourceScan
|
||||||
|
--- @return integer
|
||||||
|
local function parse_tb_bind_(source, pos, ident_end, line_of, out)
|
||||||
|
local after = duffle.skip_ws_and_cmt(source, ident_end) ---@type integer
|
||||||
|
if source:sub(after, after) ~= "(" then return ident_end end
|
||||||
|
local inner, after_p = duffle.read_parens(source, after) ---@type string|nil, integer
|
||||||
|
local args = duffle.split_top_level_commas(inner or "") ---@type string[]
|
||||||
|
local typ = duffle.trim(args[2] or "") ---@type string
|
||||||
|
if typ ~= "" then
|
||||||
|
local emits = out.tape_emits or {} ---@type TapeEmit[]
|
||||||
|
for i = #emits, 1, -1 do ---@type integer
|
||||||
|
if emits[i].binds == nil then
|
||||||
|
emits[i].binds = typ
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return after_p or (after + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param source string
|
||||||
|
--- @param pos integer
|
||||||
|
--- @param ident_end integer
|
||||||
|
--- @param line_of fun(pos: integer): integer
|
||||||
|
--- @param out SourceScan
|
||||||
|
--- @return integer
|
||||||
|
local function parse_tb_data(source, pos, ident_end, line_of, out)
|
||||||
|
local after = duffle.skip_ws_and_cmt(source, ident_end) ---@type integer
|
||||||
|
if source:sub(after, after) ~= "(" then return ident_end end
|
||||||
|
local _, after_p = duffle.read_parens(source, after) ---@type string|nil, integer
|
||||||
|
local emits = out.tape_emits or {} ---@type TapeEmit[]
|
||||||
|
local last = emits[#emits] ---@type TapeEmit|nil
|
||||||
|
if last then
|
||||||
|
last.data_words = (last.data_words or 0) + 1
|
||||||
end
|
end
|
||||||
return after_p or (after + 1)
|
return after_p or (after + 1)
|
||||||
end
|
end
|
||||||
@@ -2872,6 +3016,8 @@ end
|
|||||||
local C_STMT_PARSERS = { ---@type table<string, fun(source: string, pos: integer, ident_end: integer, line_of: fun(pos: integer): integer, out: SourceScan): integer>
|
local C_STMT_PARSERS = { ---@type table<string, fun(source: string, pos: integer, ident_end: integer, line_of: fun(pos: integer): integer, out: SourceScan): integer>
|
||||||
tb_emit_ = parse_tb_emit_,
|
tb_emit_ = parse_tb_emit_,
|
||||||
tb_emit = parse_tb_emit,
|
tb_emit = parse_tb_emit,
|
||||||
|
tb_bind_ = parse_tb_bind_,
|
||||||
|
tb_data = parse_tb_data,
|
||||||
addrs = parse_addrs_assign,
|
addrs = parse_addrs_assign,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2924,6 +3070,8 @@ local function scan_source(source, source_file, code_macros, code_macro_bodies)
|
|||||||
atoms = {},
|
atoms = {},
|
||||||
raw_atoms = {},
|
raw_atoms = {},
|
||||||
binds = {},
|
binds = {},
|
||||||
|
atom_bundles = {},
|
||||||
|
tape_emits = {},
|
||||||
atom_infos = {},
|
atom_infos = {},
|
||||||
component_atom_infos = {},
|
component_atom_infos = {},
|
||||||
macros = {},
|
macros = {},
|
||||||
@@ -3238,6 +3386,8 @@ local function merge_corpus_registries(corpus)
|
|||||||
corpus.reg_use_schemas = corpus.reg_use_schemas or {}
|
corpus.reg_use_schemas = corpus.reg_use_schemas or {}
|
||||||
corpus.reg_use_errors = corpus.reg_use_errors or {}
|
corpus.reg_use_errors = corpus.reg_use_errors or {}
|
||||||
corpus.tape_chains = corpus.tape_chains or {}
|
corpus.tape_chains = corpus.tape_chains or {}
|
||||||
|
corpus.atom_bundles = corpus.atom_bundles or {}
|
||||||
|
corpus.tape_emits = corpus.tape_emits or {}
|
||||||
|
|
||||||
-- Replace the existing corpus collections with empty tables so a re-run on the same corpus produces identical state (deterministic merge).
|
-- Replace the existing corpus collections with empty tables so a re-run on the same corpus produces identical state (deterministic merge).
|
||||||
-- This is safe because M.run is the only writer to these tables within a single orchestrator invocation.
|
-- This is safe because M.run is the only writer to these tables within a single orchestrator invocation.
|
||||||
@@ -3255,6 +3405,8 @@ local function merge_corpus_registries(corpus)
|
|||||||
"reg_use_schemas",
|
"reg_use_schemas",
|
||||||
"reg_use_errors",
|
"reg_use_errors",
|
||||||
"tape_chains",
|
"tape_chains",
|
||||||
|
"atom_bundles",
|
||||||
|
"tape_emits",
|
||||||
}) do
|
}) do
|
||||||
corpus[key] = {}
|
corpus[key] = {}
|
||||||
end
|
end
|
||||||
@@ -3362,6 +3514,55 @@ local function merge_corpus_registries(corpus)
|
|||||||
for _, chain in ipairs(scan.tape_chains or {}) do ---@type integer, TapeChain
|
for _, chain in ipairs(scan.tape_chains or {}) do ---@type integer, TapeChain
|
||||||
corpus.tape_chains[#corpus.tape_chains + 1] = chain
|
corpus.tape_chains[#corpus.tape_chains + 1] = chain
|
||||||
end
|
end
|
||||||
|
for _, emit in ipairs(scan.tape_emits or {}) do ---@type integer, TapeEmit
|
||||||
|
corpus.tape_emits[#corpus.tape_emits + 1] = emit
|
||||||
|
end
|
||||||
|
|
||||||
|
-- atom_bundles: keyed by typedef name. First-wins per name (like components).
|
||||||
|
for name, bundle in pairs(scan.atom_bundles or {}) do ---@type string, AtomBundle
|
||||||
|
if corpus.atom_bundles[name] == nil then
|
||||||
|
corpus.atom_bundles[name] = bundle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Join slot roles to AtomBundleEntry_ identities after catalogs and atoms exist.
|
||||||
|
-- Do not invent a catalog from an entry that has no typedef.
|
||||||
|
for _, bundle in pairs(corpus.atom_bundles) do ---@type string, AtomBundle
|
||||||
|
local entries = {} ---@type table<string, string>
|
||||||
|
for _, slot in ipairs(bundle.slots or {}) do ---@type integer, string
|
||||||
|
local atom_name = bundle.name .. "_" .. slot ---@type string
|
||||||
|
if corpus.atoms_by_name[atom_name] then
|
||||||
|
entries[slot] = atom_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if next(entries) then
|
||||||
|
bundle.entries = entries
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resolve tb_emit names: atom first, else unique catalog slot → entries[slot].
|
||||||
|
-- Ambiguous slot or missing entry: leave the raw ident (no A/B later).
|
||||||
|
for _, emit in ipairs(corpus.tape_emits) do ---@type integer, TapeEmit
|
||||||
|
if corpus.atoms_by_name[emit.name] == nil then
|
||||||
|
local slot = emit.slot or emit.name ---@type string
|
||||||
|
local hit = nil ---@type AtomBundle|nil
|
||||||
|
local n = 0 ---@type integer
|
||||||
|
for _, bundle in pairs(corpus.atom_bundles) do ---@type string, AtomBundle
|
||||||
|
for _, s in ipairs(bundle.slots or {}) do ---@type integer, string
|
||||||
|
if s == slot then
|
||||||
|
n = n + 1
|
||||||
|
hit = bundle
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local ident = hit and hit.entries and hit.entries[slot] ---@type string|nil
|
||||||
|
if n == 1 and ident then
|
||||||
|
emit.name = ident
|
||||||
|
emit.slot = slot
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4016,6 +4016,66 @@ end
|
|||||||
-- Each check is one table row and one `check_*` function.
|
-- Each check is one table row and one `check_*` function.
|
||||||
-- This is the plex pattern: the iteration is in ONE place (validate), the variation is in DATA (this table).
|
-- This is the plex pattern: the iteration is in ONE place (validate), the variation is in DATA (this table).
|
||||||
|
|
||||||
|
--- @param src SourceFile
|
||||||
|
--- @param pipe_ctx PassScratch
|
||||||
|
--- @param findings Finding[]
|
||||||
|
--- @return nil
|
||||||
|
local function check_tb_bind_type_match(src, pipe_ctx, findings)
|
||||||
|
local atoms_by_name = pipe_ctx.atoms_by_name or {} ---@type table<string, AtomEntry>
|
||||||
|
local info_by = {} ---@type table<string, AtomInfoEntry>
|
||||||
|
for _, info in ipairs(pipe_ctx.atom_infos_all or {}) do ---@type integer, AtomInfoEntry
|
||||||
|
info_by[info.atom_name] = info
|
||||||
|
end
|
||||||
|
for name, info in pairs(pipe_ctx.info_by_atom or {}) do ---@type string, AtomInfoEntry
|
||||||
|
info_by[name] = info
|
||||||
|
end
|
||||||
|
for _, emit in ipairs((src.scan and src.scan.tape_emits) or {}) do ---@type integer, TapeEmit
|
||||||
|
if atoms_by_name[emit.name] then
|
||||||
|
local atom_binds = info_by[emit.name] and info_by[emit.name].binds ---@type string|nil
|
||||||
|
if emit.binds and atom_binds and emit.binds ~= atom_binds then
|
||||||
|
findings[#findings + 1] = {
|
||||||
|
atom = emit.name,
|
||||||
|
line = emit.line or 0,
|
||||||
|
check = "tb_bind_type_match",
|
||||||
|
kind = "error",
|
||||||
|
msg = string.format("tb_emit '%s' binds %s but atom_bind is %s"
|
||||||
|
, emit.name, emit.binds, atom_binds),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param src SourceFile
|
||||||
|
--- @param pipe_ctx PassScratch
|
||||||
|
--- @param findings Finding[]
|
||||||
|
--- @return nil
|
||||||
|
local function check_tb_bind_required(src, pipe_ctx, findings)
|
||||||
|
local atoms_by_name = pipe_ctx.atoms_by_name or {} ---@type table<string, AtomEntry>
|
||||||
|
local info_by = {} ---@type table<string, AtomInfoEntry>
|
||||||
|
for _, info in ipairs(pipe_ctx.atom_infos_all or {}) do ---@type integer, AtomInfoEntry
|
||||||
|
info_by[info.atom_name] = info
|
||||||
|
end
|
||||||
|
for name, info in pairs(pipe_ctx.info_by_atom or {}) do ---@type string, AtomInfoEntry
|
||||||
|
info_by[name] = info
|
||||||
|
end
|
||||||
|
for _, emit in ipairs((src.scan and src.scan.tape_emits) or {}) do ---@type integer, TapeEmit
|
||||||
|
if atoms_by_name[emit.name] then
|
||||||
|
local atom_binds = info_by[emit.name] and info_by[emit.name].binds ---@type string|nil
|
||||||
|
if atom_binds and emit.binds == nil and (emit.data_words or 0) == 0 then
|
||||||
|
findings[#findings + 1] = {
|
||||||
|
atom = emit.name,
|
||||||
|
line = emit.line or 0,
|
||||||
|
check = "tb_bind_required",
|
||||||
|
kind = "error",
|
||||||
|
msg = string.format("tb_emit '%s' has atom_bind(%s) but no tb_bind_ or tb_data"
|
||||||
|
, emit.name, atom_binds),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local CHECK_RULES = { ---@type CheckRule[]
|
local CHECK_RULES = { ---@type CheckRule[]
|
||||||
{ name = "transfer_hazards", per_atom = check_transfer_hazards },
|
{ name = "transfer_hazards", per_atom = check_transfer_hazards },
|
||||||
{ name = "gte_input_latch", per_atom = check_gte_input_latch },
|
{ name = "gte_input_latch", per_atom = check_gte_input_latch },
|
||||||
@@ -4040,6 +4100,8 @@ local CHECK_RULES = { ---@type CheckRule[]
|
|||||||
{ name = "binds_no_substruct_deref", per_source = check_binds_no_substruct_deref },
|
{ name = "binds_no_substruct_deref", per_source = check_binds_no_substruct_deref },
|
||||||
{ name = "component_self_consistency", per_source = check_component_self_consistency },
|
{ name = "component_self_consistency", per_source = check_component_self_consistency },
|
||||||
{ name = "atom_calls_inferred_traffic", per_atom = check_atom_calls_inferred_traffic },
|
{ name = "atom_calls_inferred_traffic", per_atom = check_atom_calls_inferred_traffic },
|
||||||
|
{ name = "tb_bind_type_match", per_source = check_tb_bind_type_match },
|
||||||
|
{ name = "tb_bind_required", per_source = check_tb_bind_required },
|
||||||
}
|
}
|
||||||
|
|
||||||
-- ════════════════════════════════════════════════════════════════════════════
|
-- ════════════════════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ local PASS_FLAG_DISPATCH_KEY = "__pass__" ---@type string
|
|||||||
--- @field atom_phases table<string, AtomPhaseGroup>
|
--- @field atom_phases table<string, AtomPhaseGroup>
|
||||||
--- @field word_counts WordCounts
|
--- @field word_counts WordCounts
|
||||||
--- @field components table<string, Component>
|
--- @field components table<string, Component>
|
||||||
|
--- @field atom_bundles table<string, AtomBundle>|nil
|
||||||
|
--- @field tape_emits TapeEmit[]|nil
|
||||||
--- @field collisions CorpusCollision[]
|
--- @field collisions CorpusCollision[]
|
||||||
--- @field resolver SourceResolver
|
--- @field resolver SourceResolver
|
||||||
--- @field component_atom_infos AtomInfoEntry[]|nil
|
--- @field component_atom_infos AtomInfoEntry[]|nil
|
||||||
@@ -373,8 +375,7 @@ COMMON_FLAGS:
|
|||||||
--help Show this help and exit
|
--help Show this help and exit
|
||||||
|
|
||||||
EXIT CODES:
|
EXIT CODES:
|
||||||
0 All requested passes succeeded
|
0 Ran. Findings print on stderr and in the report; they do not fail the process.
|
||||||
1 Validation errors found
|
|
||||||
2 Metaprogram internal error
|
2 Metaprogram internal error
|
||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
@@ -665,6 +666,8 @@ local function build_ctx(args)
|
|||||||
atom_phases = {},
|
atom_phases = {},
|
||||||
word_counts = {},
|
word_counts = {},
|
||||||
components = {},
|
components = {},
|
||||||
|
atom_bundles = {},
|
||||||
|
tape_emits = {},
|
||||||
collisions = {},
|
collisions = {},
|
||||||
resolver = resolution.resolver,
|
resolver = resolution.resolver,
|
||||||
}
|
}
|
||||||
@@ -816,8 +819,7 @@ local function main(argv)
|
|||||||
local requested = args.requested_set ---@type string[]
|
local requested = args.requested_set ---@type string[]
|
||||||
local closed = topo_sort(PASSES, requested) ---@type string[]
|
local closed = topo_sort(PASSES, requested) ---@type string[]
|
||||||
|
|
||||||
local had_errors = dispatch_passes(ctx, closed) ---@type boolean
|
dispatch_passes(ctx, closed)
|
||||||
if had_errors then os.exit(EXIT_VALIDATION_ERRORS) end
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
|
|||||||
Reference in New Issue
Block a user