mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-14 11:38:14 +00:00
more review, made a register file allocator (drafted, kinda iffy, want todo comp-time as well).
This commit is contained in:
@@ -97,6 +97,7 @@
|
||||
#define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len))
|
||||
#define Array_(type,len) Array_expand(type,len)
|
||||
#define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b
|
||||
#define Bitmask_(b) (1u << b)
|
||||
#define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol
|
||||
#define Proc_(symbol) symbol
|
||||
#define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another.
|
||||
@@ -199,6 +200,8 @@ def_signed_ops(le, <=)
|
||||
#define defer_info(type,expr, ...) for(type info= {__VA_ARGS__}; info.once!=1;++info.once,(expr)) // Defer with tracked state
|
||||
|
||||
#define do_while(cond) for (U8 once=0; once!=1 || (cond); ++once)
|
||||
|
||||
#define Jmp_nZero_(cond,label) if (cond) goto label;
|
||||
#pragma endregion Control Flow & Iteration
|
||||
|
||||
#define span_iter(type, iter, m_begin, op, m_end) ( \
|
||||
|
||||
@@ -237,16 +237,16 @@ WORD_COUNT(mac_format_g4_color, 12)
|
||||
WORD_COUNT(mac_insert_ot_tag, 11)
|
||||
|
||||
/* atom_dbg_skip */
|
||||
#define mac_pad_set_centered_axes(r_state, r_scratch) \
|
||||
load_upper_i(r_scratch, (PadAxis_Centered_Word >> 16) & 0xFFFF) \
|
||||
, or_i_self( r_scratch, PadAxis_Centered_Word & 0xFFFF) \
|
||||
, store_word( r_scratch, r_state, O_(PadState,axes))
|
||||
#define mac_pad_set_centered_axes(state, scratch) \
|
||||
load_upper_i(scratch, (PadAxis_Centered >> 16) & 0xFFFF) \
|
||||
, or_i_self( scratch, PadAxis_Centered & 0xFFFF) /* mac_load_word_imm(scratch, PadAxis_Centered), */ \
|
||||
, store_word( scratch, state, O_(PadState,axes))
|
||||
WORD_COUNT(mac_pad_set_centered_axes, 3)
|
||||
|
||||
/* atom_dbg_skip */
|
||||
#define mac_pad_set_id_byte(r_state, r_id, id_value) \
|
||||
#define mac_pad_set_id_byte(state, r_id, id_value) \
|
||||
add_ui( r_id, R_0, id_value) \
|
||||
, store_byte(r_id, r_state, O_(PadState,id))
|
||||
, store_byte(r_id, state, O_(PadState,id))
|
||||
WORD_COUNT(mac_pad_set_id_byte, 2)
|
||||
|
||||
/* atom_dbg_skip */
|
||||
|
||||
+5
-10
@@ -8,40 +8,35 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(gp_atom_c);
|
||||
|
||||
#pragma region MACs (Mips Atom Components)
|
||||
|
||||
atom_dbg_skip
|
||||
FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U4 cmd, U4 reg_transfer, U4 reg_base, U2 port)
|
||||
MipsAtomComp_Proc_(ab, {
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
mac_load_word_imm(reg_transfer, cmd),
|
||||
store_word( reg_transfer, reg_base, port),
|
||||
})
|
||||
|
||||
atom_dbg_skip
|
||||
FI_ Slice_MipsCode ac_store_rgb8(AtomBuilder_R ab, U1 rr, U1 rg, U1 rb, U4 base, U4 offset)
|
||||
MipsAtomComp_Proc_(ab, {
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
store_byte(rr, base, offset + O_(RGB8,r)),
|
||||
store_byte(rg, base, offset + O_(RGB8,g)),
|
||||
store_byte(rb, base, offset + O_(RGB8,b)),
|
||||
})
|
||||
|
||||
atom_dbg_skip
|
||||
FI_ Slice_MipsCode ac_pack_color_word(AtomBuilder_R ab, U4 r_base, U4 off, U4 cmd, U1 r, U1 g, U1 b)
|
||||
MipsAtomComp_Proc_(ab, {
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
load_upper_i(R_AT, (cmd) << 8 | (b)),
|
||||
or_i_self( R_AT, ((g) << 8) | (r)),
|
||||
store_word( R_AT, r_base, (off)),
|
||||
})
|
||||
|
||||
atom_dbg_skip
|
||||
FI_ Slice_MipsCode ac_format_f3_color(AtomBuilder_R ab, U4 r_base, U1 r, U1 g, U1 b)
|
||||
MipsAtomComp_Proc_(ab, { mac_pack_color_word(r_base, O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) })
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, { mac_pack_color_word(r_base, O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) })
|
||||
|
||||
atom_dbg_skip
|
||||
FI_ Slice_MipsCode ac_format_g4_color(AtomBuilder_R ab, U4 r_prim_cursor,
|
||||
U1 r0, U1 g0, U1 b0,
|
||||
U1 r1, U1 g1, U1 b1,
|
||||
U1 r2, U1 g2, U1 b2,
|
||||
U1 r3, U1 g3, U1 b3)
|
||||
MipsAtomComp_Proc_(ab, {
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c0), gp0_cmd_poly_g4, r0,g0,b0),
|
||||
mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c1), 0, r1,g1,b1),
|
||||
mac_pack_color_word(r_prim_cursor, O_(Poly_G4,c2), 0, r2,g2,b2),
|
||||
|
||||
@@ -143,7 +143,7 @@ FI_ Slice_MipsCode ac_trans_mt3s3s4(AtomBuilder_R ab
|
||||
* The later 64 entries (octaves 2-3) are the `srav` branch when the magnitude's top bit is well above bit 24.
|
||||
*
|
||||
* 192-entry table is reproduced verbatim from libgte (verified against libpsn00b/psxgte/vector.s:100-123 — 24 rows × 8 halfwords, last entry 0x0804). */
|
||||
internal RO_ S2 gte_normalize_sqr_tbl[192] align_(2) = {
|
||||
internal S2 const gte_normalize_sqr_tbl[192] align_(2) = {
|
||||
0x1000, 0x0fe0, 0x0fc1, 0x0fa3, 0x0f85, 0x0f68, 0x0f4c, 0x0f30,
|
||||
0x0f15, 0x0efb, 0x0ee1, 0x0ec7, 0x0eae, 0x0e96, 0x0e7e, 0x0e66,
|
||||
0x0e4f, 0x0e38, 0x0e22, 0x0e0c, 0x0df7, 0x0de2, 0x0dcd, 0x0db9,
|
||||
@@ -309,7 +309,7 @@ internal MipsAtom_(set_gte_mt3s2s4) atom_info(
|
||||
load_word(R_T3, R_TapePtr, O_(Binds_SetGteMT3S2S4,transform)),
|
||||
add_ui_self( R_TapePtr, S_(Binds_SetGteMT3S2S4)),
|
||||
/* Load 3x3 Rotation + 3x1 Translation from R_T3 into GTE CONTROL Regs (ctc2) */
|
||||
load_word(R_T0, R_T3, 0), load_word(R_T1, R_T3, 4),
|
||||
load_word(R_T0, R_T3, 0), load_word(R_T1, R_T3, 4),
|
||||
gte_mv_to_ctrl_r(R_T0, gte_cr_RT11), gte_mv_to_ctrl_r(R_T1, gte_cr_RT12),
|
||||
load_word(R_T0, R_T3, 8), load_word(R_T1, R_T3, 12), load_word(R_T2, R_T3, 16),
|
||||
gte_mv_to_ctrl_r(R_T0, gte_cr_RT13), gte_mv_to_ctrl_r(R_T1, gte_cr_RT21), gte_mv_to_ctrl_r(R_T2, gte_cr_RT22),
|
||||
|
||||
+73
-25
@@ -139,19 +139,17 @@ typedef Slice_(MipsAtom);
|
||||
// atombuilder_push(ab, slice_from_array(MipsCode, atom_comp_code));
|
||||
// }
|
||||
// The body must NOT include mac_yield() (the parent atom yields).
|
||||
// The component name is derived by the Lua metaprogram from the preceding
|
||||
// `FI_ Slice_MipsCode ac_X(...)` declaration (backward walk from the macro site).
|
||||
// Inline-only callers (the generated `mac_<name>` aliases) skip the `ab` arg via metaprogram filtering;
|
||||
// escape callers (ac_<name> invoked as a function) pass a long-lived builder.
|
||||
// The component name is derived by the Lua metaprogram from the preceding `FI_ Slice_MipsCode ac_X(...)` declaration (backward walk from the macro site).
|
||||
// Inline-only callers (the generated `mac_<name>` aliases) skip the `ab` arg via metaprogram filtering; escape callers (ac_<name> invoked as a function) pass a long-lived builder.
|
||||
#define MipsAtomComp_Proc_(ab, ...) { MipsCode atom_comp_code[] align_(4) = __VA_ARGS__; atombuilder_push(ab, slice_from_array(MipsCode, atom_comp_code)); }
|
||||
|
||||
/* 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.
|
||||
Place `ATOM_FILE_LINE_MARKER();` once at file scope in any `.atom.c` that defines atoms.
|
||||
The macro expands to a file-scope `internal U4 const` declaration keeps the file in the line table.
|
||||
The constant is in `.rodata` and unreferenced; the linker may eliminate it.
|
||||
The two-level concat + `__LINE__` suffix makes the identifier unique per call site
|
||||
(the identifier embeds the source line, so duplicates across `#include`d files don't collide). */
|
||||
Macro expands to a file-scope `internal U4 const` declaration keeps the file in the line table.
|
||||
The constant is in `.rodata` so the linker may eliminate it.
|
||||
Two-level concat + `__LINE__` suffix makes the identifier unique per call site
|
||||
(identifier embeds the source line, so duplicates across `#include`d files don't collide). */
|
||||
#define ATOM_FILE_DEBUGGER_LINE_MARKER(file_name) internal U4 const tmpl(atom_file_debugger_line_marker,file_name) = 0
|
||||
|
||||
typedef Slice_MipsAtom Tape;
|
||||
@@ -294,29 +292,79 @@ FI_ void atomarena_reset(AtomArena_R aa) { aa->used = 0; }
|
||||
#pragma region RegFile (Register File Allocator)
|
||||
// A specialized allocator utilized to help the user track which registers are bound to values
|
||||
// that must be preserved for the arena's bounds.
|
||||
// TODO(Ed): Technically we can do this at comp-time with the metaprogram, but we may have namespace conflicts.
|
||||
// Unless we follow a convention for #define <Scope_Prefix> or something per register allocation boundary.
|
||||
|
||||
enum {
|
||||
RegFileArena_Len,
|
||||
};
|
||||
typedef Enum_(U4, RegFileEntry) {
|
||||
// TODO(Ed): Define RF_Field, each field is maped by index + bit pos.
|
||||
// the index is the upper portion of a U4 and the bit pos in the lower pos.
|
||||
/* ABI + tape reserves that are never handed out by alloc. */
|
||||
U4 const regfile_abi_mask =
|
||||
(1u << R_0) | (1u << R_AT) |
|
||||
(1u << R_K0) | (1u << R_K1) |
|
||||
(1u << R_GP) | (1u << R_SP) |
|
||||
(1u << R_FP) | (1u << R_RA) |
|
||||
(1u << R_T8) | (1u << R_T9); /* AtomJmp + TapePtr */
|
||||
|
||||
regfileentry_todo_,
|
||||
// TODO(Ed): Is there a trick we can do with the current register enums to
|
||||
// just resolve an entry automatically when doing a pin?
|
||||
};
|
||||
typedef Struct_(RegFile) {
|
||||
U1 GPR[RegFileArena_Len];
|
||||
U1 GTE[RegFileArena_Len];
|
||||
U1 GP[RegFileArena_Len];
|
||||
A2_U2 GPR;
|
||||
A2_U2 GTE;
|
||||
};
|
||||
|
||||
void regfile_pin(U4 register) {
|
||||
|
||||
assert(false);
|
||||
typedef Struct_(RegFile_RInfo) {
|
||||
U2_R section;
|
||||
U2 mask;
|
||||
B2 occupied;
|
||||
};
|
||||
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; }
|
||||
|
||||
FI_ RegFile_RInfo regfile_rinfo(A2_U2 file, Reg r_id) {
|
||||
U2 s_id = r_id >> 4;
|
||||
U2_R section = & file[s_id];
|
||||
U2 mask = (1u << (r_id & 15));
|
||||
B2 occupied = section[0] & mask != 0;
|
||||
return (RegFile_RInfo){section, mask, occupied};
|
||||
}
|
||||
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;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
I_ Reg regfile_alloc(RegFile_R rf) {
|
||||
U2 allocated = 0;
|
||||
for range_iter(r_id, <=, r1u2(R_T0, R_T7)) {
|
||||
allocated = regfile__alloc_helper(rf->GPR, r_id); Jmp_nZero_(allocated,resolved);
|
||||
}
|
||||
for range_iter(r_id, <=, r1u2(R_V0, R_V1)) {
|
||||
allocated = regfile__alloc_helper(rf->GPR, r_id); Jmp_nZero_(allocated,resolved);
|
||||
}
|
||||
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);
|
||||
info.section[0] |= info.mask;
|
||||
return r_id;
|
||||
}
|
||||
FI_ void regfile_free_mask(RegFile_R rf, U4 mask) {
|
||||
if (regfile_abi_mask & mask) return;
|
||||
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;
|
||||
RegFile_RInfo info = regfile_rinfo(rf->GPR, r_id);
|
||||
info.section[0] &= ~info.mask;
|
||||
}
|
||||
FI_ void regfile_reset(RegFile_R rf) {
|
||||
rf->GPR[0] = u4_lo(regfile_abi_mask);
|
||||
rf->GPR[1] = u4_hi(regfile_abi_mask);
|
||||
}
|
||||
#pragma endregion RegFileArena (Register File Allocator)
|
||||
|
||||
#pragma region Mips Atom Procs
|
||||
|
||||
+15
-14
@@ -11,16 +11,16 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(pad_atom_c);
|
||||
|
||||
#pragma region MACs (Mips Atom Components)
|
||||
|
||||
FI_ Slice_MipsCode ac_pad_set_centered_axes(AtomBuilder_R ab, U4 r_state, U4 r_scratch) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
load_upper_i(r_scratch, (PadAxis_Centered_Word >> 16) & 0xFFFF),
|
||||
or_i_self( r_scratch, PadAxis_Centered_Word & 0xFFFF),
|
||||
store_word( r_scratch, r_state, O_(PadState,axes)),
|
||||
FI_ Slice_MipsCode ac_pad_set_centered_axes(AtomBuilder_R ab, Reg state, Reg scratch) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
load_upper_i(scratch, (PadAxis_Centered >> 16) & 0xFFFF),
|
||||
or_i_self( scratch, PadAxis_Centered & 0xFFFF),
|
||||
// mac_load_word_imm(scratch, PadAxis_Centered),
|
||||
store_word( scratch, state, O_(PadState,axes)),
|
||||
})
|
||||
|
||||
FI_ Slice_MipsCode ac_pad_set_id_byte(AtomBuilder_R ab, U1 r_state, U1 r_id, U1 id_value)
|
||||
atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
FI_ Slice_MipsCode ac_pad_set_id_byte(AtomBuilder_R ab, Reg state, Reg r_id, U1 id_value) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
add_ui( r_id, R_0, id_value),
|
||||
store_byte(r_id, r_state, O_(PadState,id)),
|
||||
store_byte(r_id, state, O_(PadState,id)),
|
||||
})
|
||||
|
||||
FI_ Slice_MipsCode ac_pad_set_status(AtomBuilder_R ab, U4 r_tmp, U1 r_state, U4 pad_status) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
||||
@@ -55,12 +55,12 @@ FI_ Slice_MipsCode ac_pad_store_inverted_buttons(AtomBuilder_R ab, U1 r_buttons,
|
||||
* byte_swap16(x) = (x >> 8) | (x << 8); nor(x, R_0) = ~x. store_half truncates to 16 bits so the upper-16 mask is implicit in the store.
|
||||
*
|
||||
* Register use (atom-local; no wave-context touched):
|
||||
* R_T0 = raw base (kept throughout; axes loads read raw[4..7] from R_T0)
|
||||
* R_T1 = state base (kept throughout; all stores go through R_T1)
|
||||
* R_T2 = raw[0] status (alive across the disc/pending/id dispatch, then dead)
|
||||
* R_T3 = raw[1] id (alive across the id dispatch, then dead)
|
||||
* R_T4 = scratch (shifts, compares, immediate loads, store values)
|
||||
* R_T5 = scratch (parallel lui+ori for the 0x80808080 axes constant + byte-swap target)
|
||||
* R_T0 = raw base : Kept throughout; axes loads read raw[4..7] from R_T0.
|
||||
* R_T1 = state base : Kept throughout; all stores go through R_T1.
|
||||
* R_T2 = raw[0] status : Alive across the disc/pending/id dispatch, then dead.
|
||||
* R_T3 = raw[1] id : Alive across the id dispatch, then dead.
|
||||
* R_T4 = scratch : Shifts, compares, immediate loads, store values.
|
||||
* R_T5 = scratch : Parallel lui + ori for the 0x80808080 axes constant + byte-swap target.
|
||||
*/
|
||||
enum {
|
||||
R_PadRaw = R_T0 atom_reg atom_type(U1),
|
||||
@@ -125,7 +125,8 @@ atom_label(id_dispatch) /* === Case 3-6: ID dispatch */
|
||||
* R_T5 is then "dead" — only consumed at the analog_pad range check downstream. */
|
||||
mac_pad_set_status(R_T4, R_PadState, PadStatus_Digital),
|
||||
load_half_u( R_T4, R_PadRaw, O_(PadBiosRaw, buttons)), /* R_T4 = raw_buttons; */
|
||||
load_upper_i(R_T5, PadAxis_Centered_Hi), or_i_self(R_T5, PadAxis_Centered_Lo), /* fills the buttons-load's delay slot (doesn't read R_T4) */
|
||||
mac_load_word_imm(R_T5, PadAxis_Centered), /* fills the buttons-load's delay slot (doesn't read R_T4) */
|
||||
// load_upper_i(R_T5, PadAxis_Centered_Hi), or_i_self(R_T5, PadAxis_Centered_Lo),
|
||||
mac_pad_store_inverted_buttons(R_T4, R_PadState), /* R_T4 settled: nor + sh writes ~raw_buttons to state.buttons */
|
||||
store_word(R_T5, R_PadState, O_(PadState, axes)), /* single sw writes the 4-byte axes block at offset 8 (left_x, left_y, right_x, right_y) */
|
||||
mac_pad_set_id_byte(R_PadState, R_T4, PadRawId_Digital),
|
||||
|
||||
+3
-3
@@ -81,9 +81,9 @@ typedef Enum_(U1, PadUnknownId) {
|
||||
PadUnknownId_Sentinel = 0xFF,
|
||||
};
|
||||
typedef Enum_(U4, PadAxisCentered) {
|
||||
PadAxis_Centered_Hi = 0x8080,
|
||||
PadAxis_Centered_Lo = 0x8080,
|
||||
PadAxis_Centered_Word = 0x80808080U,
|
||||
PadAxis_Centered_Hi = 0x8080,
|
||||
PadAxis_Centered_Lo = 0x8080,
|
||||
PadAxis_Centered = 0x80808080U,
|
||||
};
|
||||
typedef Enum_(U1, PadDeadZone) {
|
||||
PadDeadZone_LowBound = 0x70, /* left_x < LowBound → active; delta = 0x80 - left_x > 0 (rightward pull) */
|
||||
|
||||
Reference in New Issue
Block a user