mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-25 02:20:33 +00:00
Reviewing. Successfuly reworked register allocation for tape runs.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#ifdef INTELLISENSE_DIRECTIVES
|
#ifdef INTELLISENSE_DIRECTIVES
|
||||||
# pragma once
|
# pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
bios_init_pad_2 = 0x12,
|
bios_init_pad_2 = 0x12,
|
||||||
bios_start_pad_2 = 0x13,
|
bios_start_pad_2 = 0x13,
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ WORD_COUNT(mac_gte_sqr_v3s4, 5)
|
|||||||
, gte_mv_to_data_r(r_sx, C2_IR1) \
|
, gte_mv_to_data_r(r_sx, C2_IR1) \
|
||||||
, gte_mv_to_data_r(r_sy, C2_IR2) \
|
, gte_mv_to_data_r(r_sy, C2_IR2) \
|
||||||
, gte_mv_to_data_r(r_sz, C2_IR3) \
|
, gte_mv_to_data_r(r_sz, C2_IR3) \
|
||||||
, nop2 /* retire IR0..IR3 → GPF input pre-fill (matches libgte 0x80016134..0x80016138) */ \
|
, GteDelay_ nop2 /* retire IR0..IR3 → GPF input pre-fill (matches libgte 0x80016134..0x80016138) */ \
|
||||||
, gte_cmdw_gpf \
|
, gte_cmdw_gpf \
|
||||||
, gte_mv_from_data_r(r_dx, C2_MAC1) \
|
, gte_mv_from_data_r(r_dx, C2_MAC1) \
|
||||||
, gte_mv_from_data_r(r_dy, C2_MAC2) \
|
, gte_mv_from_data_r(r_dy, C2_MAC2) \
|
||||||
@@ -291,7 +291,7 @@ WORD_COUNT(mac_gte_sqr_v3s4, 5)
|
|||||||
, shift_aright_var(r_dx, r_dx, r_shift) \
|
, shift_aright_var(r_dx, r_dx, r_shift) \
|
||||||
, shift_aright_var(r_dy, r_dy, r_shift) \
|
, shift_aright_var(r_dy, r_dy, r_shift) \
|
||||||
, shift_aright_var(r_dz, r_dz, r_shift)
|
, shift_aright_var(r_dz, r_dz, r_shift)
|
||||||
WORD_COUNT(mac_gte_gpf_scale, 13)
|
WORD_COUNT(mac_gte_gpf_scale, 12)
|
||||||
|
|
||||||
#define mac_trans_mt3s3s4(r_mtx, r_off, r_t0, r_t1, r_t2) \
|
#define mac_trans_mt3s3s4(r_mtx, r_off, r_t0, r_t1, r_t2) \
|
||||||
load_word( r_t0, r_off, O_(V3_S4,x)) \
|
load_word( r_t0, r_off, O_(V3_S4,x)) \
|
||||||
|
|||||||
+24
-18
@@ -118,7 +118,7 @@ atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
|||||||
gte_mv_to_data_r(r_sx, C2_IR1),
|
gte_mv_to_data_r(r_sx, C2_IR1),
|
||||||
gte_mv_to_data_r(r_sy, C2_IR2),
|
gte_mv_to_data_r(r_sy, C2_IR2),
|
||||||
gte_mv_to_data_r(r_sz, C2_IR3),
|
gte_mv_to_data_r(r_sz, C2_IR3),
|
||||||
nop2, /* retire IR0..IR3 → GPF input pre-fill (matches libgte 0x80016134..0x80016138) */
|
GteDelay_ nop2, /* retire IR0..IR3 → GPF input pre-fill (matches libgte 0x80016134..0x80016138) */
|
||||||
gte_cmdw_gpf,
|
gte_cmdw_gpf,
|
||||||
gte_mv_from_data_r(r_dx, C2_MAC1),
|
gte_mv_from_data_r(r_dx, C2_MAC1),
|
||||||
gte_mv_from_data_r(r_dy, C2_MAC2),
|
gte_mv_from_data_r(r_dy, C2_MAC2),
|
||||||
@@ -146,20 +146,17 @@ FI_ Slice_MipsCode ac_trans_mt3s3s4(AtomBuilder_R ab
|
|||||||
})
|
})
|
||||||
|
|
||||||
/* ─── LZCR ROUND EVEN + HALF-SHIFT ───
|
/* ─── LZCR ROUND EVEN + HALF-SHIFT ───
|
||||||
* Takes the raw LZCR leading-zero/ones count (from mfc2 C2_LZCR, range 1..32
|
* Takes the raw LZCR leading-zero/ones count (from mfc2 C2_LZCR, range 1..32 per PSX-SPX cop2r31) and the |v|² sum (in r_mag_sq from the MAC1+MAC2+MAC3 add).
|
||||||
* per PSX-SPX cop2r31) and the |v|² sum (in r_mag_sq from the MAC1+MAC2+MAC3
|
* Produces:
|
||||||
* add). Produces:
|
|
||||||
* r_shift ← LZCR rounded down to even (clear bit 0)
|
* r_shift ← LZCR rounded down to even (clear bit 0)
|
||||||
* r_mag_sq_copy ← |v|² sum (moved out of r_mag_sq before it's overwritten)
|
* r_mag_sq_copy ← |v|² sum (moved out of r_mag_sq before it's overwritten)
|
||||||
* r_mag_sq ← (31 - even_LZCR) / 2 = the final srav/GPF shift amount
|
* r_mag_sq ← (31 - even_LZCR) / 2 = the final srav/GPF shift amount
|
||||||
*
|
*
|
||||||
* Rounding to even ensures (31 - LZCR) is always odd, so the >> 1 division
|
* Rounding to even ensures (31 - LZCR) is always odd, so the >> 1 division is consistent — no 0.5 loss.
|
||||||
* is consistent — no 0.5 loss. The caller branches on LZCR < 24 to decide
|
* The caller branches on LZCR < 24 to decide left-shift vs right-shift of r_mag_sq_copy, then saves the shift count.
|
||||||
* left-shift vs right-shift of r_mag_sq_copy, then saves the shift count.
|
|
||||||
*
|
*
|
||||||
* Note: C2_LZCR (cop2r31) is a fixed read-only C2 data register — the caller
|
* Note: C2_LZCR (cop2r31) is a fixed read-only C2 data register — the caller must read it via mfc2 from C2_LZCR;
|
||||||
* must read it via mfc2 from C2_LZCR; there is no register choice at the
|
* there is no register choice at the hardware level. Only the GPR that holds the result is caller-determined. */
|
||||||
* hardware level. Only the GPR that holds the result is caller-determined. */
|
|
||||||
FI_ Slice_MipsCode ac_lzcr_round_even_half_shift(AtomBuilder_R ab,
|
FI_ Slice_MipsCode ac_lzcr_round_even_half_shift(AtomBuilder_R ab,
|
||||||
U4 r_shift,
|
U4 r_shift,
|
||||||
U4 r_mag_sq,
|
U4 r_mag_sq,
|
||||||
@@ -206,8 +203,7 @@ FI_ Slice_MipsCode ac_gte_mv_from_mac123_v3s4(AtomBuilder_R ab, Reg_(V3_S4) v) M
|
|||||||
|
|
||||||
/* ─── Local copy of PSYQ's sqrtbl (1/sqrt lookup table for VectorNormal). ───
|
/* ─── Local copy of PSYQ's sqrtbl (1/sqrt lookup table for VectorNormal). ───
|
||||||
* Source: PSYQ 4.7 libgte sqrtbl at 0x800185B4 in hello_camera.elf.
|
* Source: PSYQ 4.7 libgte sqrtbl at 0x800185B4 in hello_camera.elf.
|
||||||
* objdump -s --start-address=0x800185B4 --stop-address=0x800185F4 hello_camera.elf
|
* objdump -s --start-address=0x800185B4 --stop-address=0x800185F4 hello_camera.elf → 192 entries × 16-bit signed, in 1.12 fixed-point (max value 0x1000 = 1.0).
|
||||||
* → 192 entries × 16-bit signed, in 1.12 fixed-point (max value 0x1000 = 1.0).
|
|
||||||
*
|
*
|
||||||
* Data is identical to the libgte original (byte-for-byte verified).
|
* Data is identical to the libgte original (byte-for-byte verified).
|
||||||
*
|
*
|
||||||
@@ -400,12 +396,22 @@ internal MipsAtom_(set_gte_mt3s2s4) atom_info(
|
|||||||
load_word(R_T3, R_TapePtr, O_(Binds_SetGteMT3S2S4,transform)),
|
load_word(R_T3, R_TapePtr, O_(Binds_SetGteMT3S2S4,transform)),
|
||||||
add_ui_self( R_TapePtr, S_(Binds_SetGteMT3S2S4)),
|
add_ui_self( R_TapePtr, S_(Binds_SetGteMT3S2S4)),
|
||||||
/* Load 3x3 Rotation + 3x1 Translation from R_T3 into GTE CONTROL Regs (ctc2) */
|
/* 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),
|
||||||
gte_mv_to_ctrl_r(R_T0, gte_cr_RT11), gte_mv_to_ctrl_r(R_T1, gte_cr_RT12),
|
load_word(R_T1, R_T3, 4),
|
||||||
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_RT11),
|
||||||
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),
|
gte_mv_to_ctrl_r(R_T1, gte_cr_RT12),
|
||||||
load_word(R_T0, R_T3, 20), load_word(R_T1, R_T3, 24), load_word(R_T2, R_T3, 28),
|
load_word(R_T0, R_T3, 8),
|
||||||
gte_mv_to_ctrl_r(R_T0, gte_cr_TRX), gte_mv_to_ctrl_r(R_T1, gte_cr_TRY), gte_mv_to_ctrl_r(R_T2, gte_cr_TRZ),
|
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),
|
||||||
|
load_word(R_T0, R_T3, 20),
|
||||||
|
load_word(R_T1, R_T3, 24),
|
||||||
|
load_word(R_T2, R_T3, 28),
|
||||||
|
gte_mv_to_ctrl_r(R_T0, gte_cr_TRX),
|
||||||
|
gte_mv_to_ctrl_r(R_T1, gte_cr_TRY),
|
||||||
|
gte_mv_to_ctrl_r(R_T2, gte_cr_TRZ),
|
||||||
mac_yield()
|
mac_yield()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+7
-14
@@ -16,9 +16,6 @@
|
|||||||
* gte_mv_to_data_r (gte + mv + to + data + register)
|
* gte_mv_to_data_r (gte + mv + to + data + register)
|
||||||
* gte_lw_v0_xy(base) (gte + lw + v0 + xy)
|
* gte_lw_v0_xy(base) (gte + lw + v0 + xy)
|
||||||
* load_upper_i (load-upper + immediate, unique verb)
|
* load_upper_i (load-upper + immediate, unique verb)
|
||||||
*
|
|
||||||
* Vendor mnemonics (gte_mtc2, gte_mfc2, gte_lwc2, gte_swc2, etc.) are NOT in this header.
|
|
||||||
* They are in the opt-in `gte_vendor_sym.h` for users who prefer the textbook MIPS assembly mnemonics.
|
|
||||||
* ============================================================================ */
|
* ============================================================================ */
|
||||||
|
|
||||||
#ifdef INTELLISENSE_DIRECTIVES
|
#ifdef INTELLISENSE_DIRECTIVES
|
||||||
@@ -442,9 +439,8 @@ enum { _C2_TX_SUBS_ = 0
|
|||||||
/* MVMVA: sf=1 (>>12), mx=0 (RT matrix), v=0 (V0), cv=3 (no TR). */
|
/* MVMVA: sf=1 (>>12), mx=0 (RT matrix), v=0 (V0), cv=3 (no TR). */
|
||||||
#define gte_cmdw_mvmva_sf1_mx0_v0_cv3 (gte_cmd_base | enc_gte_sf(1) | enc_gte_cv(3) | enc_gte_v(0) | enc_gte_mx(0) | enc_gte_cmd(gte_cmd_mvmva))
|
#define gte_cmdw_mvmva_sf1_mx0_v0_cv3 (gte_cmd_base | enc_gte_sf(1) | enc_gte_cv(3) | enc_gte_v(0) | enc_gte_mx(0) | enc_gte_cmd(gte_cmd_mvmva))
|
||||||
|
|
||||||
/* RTPS with sf=1 (12-bit shift, no translation): matches the output of libgte's
|
/* RTPS with sf=1 (12-bit shift, no translation): matches the output of libgte's ApplyMatrixLV when the GTE pipeline expects R*pos >> 12.
|
||||||
* ApplyMatrixLV when the GTE pipeline expects R*pos >> 12. The shift produces
|
* The shift produces values like (-270, 710, 1713) which match the C11 reference path. */
|
||||||
* values like (-270, 710, 1713) which match the C11 reference path. */
|
|
||||||
#define gte_cmdw_rtps_sf1 (gte_cmd_base | enc_gte_sf(1) | enc_gte_cv(3) | enc_gte_cmd(gte_cmd_rtps))
|
#define gte_cmdw_rtps_sf1 (gte_cmd_base | enc_gte_sf(1) | enc_gte_cv(3) | enc_gte_cmd(gte_cmd_rtps))
|
||||||
|
|
||||||
/* SQR / GPF cosmetic-bits compat helpers.
|
/* SQR / GPF cosmetic-bits compat helpers.
|
||||||
@@ -477,10 +473,8 @@ enum { _C2_TX_SUBS_ = 0
|
|||||||
* bits 24-20 = 0x19 (libgte "nonsense SDK command number" signature) */
|
* bits 24-20 = 0x19 (libgte "nonsense SDK command number" signature) */
|
||||||
#define gte_cmdw_gpf (gte_cmd_base | enc_gte_cmd(gte_cmd_gpf) | gte_cmdw_gpf_fake_sig)
|
#define gte_cmdw_gpf (gte_cmd_base | enc_gte_cmd(gte_cmd_gpf) | gte_cmdw_gpf_fake_sig)
|
||||||
|
|
||||||
/* Mask to round LZCR (leading-zero/ones count, range 1..32 per PSX-SPX cop2r31)
|
/* Mask to round LZCR (leading-zero/ones count, range 1..32 per PSX-SPX cop2r31) down to even.
|
||||||
* down to even. The normalize_v3s4 half-shift logic computes (31 - LZCR) >> 1;
|
* The normalize_v3s4 half-shift logic computes (31 - LZCR) >> 1; clearing bit 0 ensures the subtraction result is always odd, so the >> 1 division is consistent (no 0.5 loss). */
|
||||||
* clearing bit 0 ensures the subtraction result is always odd,
|
|
||||||
* so the >> 1 division is consistent (no 0.5 loss). */
|
|
||||||
enum {
|
enum {
|
||||||
gte_lzcr_even_mask = 0xFFFE, /* all bits except bit 0 */
|
gte_lzcr_even_mask = 0xFFFE, /* all bits except bit 0 */
|
||||||
};
|
};
|
||||||
@@ -587,8 +581,8 @@ enum {
|
|||||||
|
|
||||||
/* gte_load_v0v1v2(p0, p1, p2, b0, b1, b2) — prelude to gte_cmd_rtpt.
|
/* gte_load_v0v1v2(p0, p1, p2, b0, b1, b2) — prelude to gte_cmd_rtpt.
|
||||||
*
|
*
|
||||||
* Loads all three GTE input vectors (6 words) from three separate pointers, one per GTE vector register,
|
* Loads all three GTE input vectors (6 words) from three separate pointers, one per GTE vector register, each loaded from its own base GPR.
|
||||||
* each loaded from its own base GPR. Caller must bind each `pN` to `bN` via a register variable.
|
* Caller must bind each `pN` to `bN` via a register variable.
|
||||||
* register V3_S2* p0 rgcc(R_T4) = verts[0].ptr; // → __asm__("$12")
|
* register V3_S2* p0 rgcc(R_T4) = verts[0].ptr; // → __asm__("$12")
|
||||||
* register V3_S2* p1 rgcc(R_T5) = verts[1].ptr; // → __asm__("$13")
|
* register V3_S2* p1 rgcc(R_T5) = verts[1].ptr; // → __asm__("$13")
|
||||||
* register V3_S2* p2 rgcc(R_T6) = verts[2].ptr; // → __asm__("$14")
|
* register V3_S2* p2 rgcc(R_T6) = verts[2].ptr; // → __asm__("$14")
|
||||||
@@ -682,8 +676,7 @@ enum {
|
|||||||
* Loads the 3x3 rotation matrix at `r0` into the GTE's rotation-matrix control registers (RT11..RT22, indices 0..4) via ctc2.
|
* Loads the 3x3 rotation matrix at `r0` into the GTE's rotation-matrix control registers (RT11..RT22, indices 0..4) via ctc2.
|
||||||
*
|
*
|
||||||
* Memory layout at r0: five contiguous 32-bit words (offsets 0..16), each holding two packed 16-bit matrix elements.
|
* Memory layout at r0: five contiguous 32-bit words (offsets 0..16), each holding two packed 16-bit matrix elements.
|
||||||
* The first 1.5 rows of a standard PSX SDK MATRIX struct (where each row is laid out as
|
* The first 1.5 rows of a standard PSX SDK MATRIX struct (where each row is laid out as [RT_xx, RT_xy] | [RT_xz, pad] | ...).
|
||||||
* [RT_xx, RT_xy] | [RT_xz, pad] | ...).
|
|
||||||
*
|
*
|
||||||
* Generated MIPS (mirrors the source macro):
|
* Generated MIPS (mirrors the source macro):
|
||||||
* lw $12, 0( %0 ) ; word 0
|
* lw $12, 0( %0 ) ; word 0
|
||||||
|
|||||||
+122
-84
@@ -66,40 +66,53 @@
|
|||||||
* */
|
* */
|
||||||
/* Register Allocation Info */
|
/* Register Allocation Info */
|
||||||
enum {
|
enum {
|
||||||
R_AtomJmp = R_T8 atom_reg, /* debug-visible; tape yield handshake scratch */
|
R_ScratchBase = R_SP atom_reg, /* Scratchpad base address (host frame top) */
|
||||||
R_TapePtr = R_T9 atom_reg, /* The Instruction Stream Pointer */
|
R_AtomJmp = R_FP atom_reg, /* Next atom target (yield handshake scratch) */
|
||||||
|
R_TapePtr = R_RA atom_reg, /* The Instruction Stream Pointer */
|
||||||
/* Stringification codes for the GCC inline assembler clobber lists. */
|
/* Stringification codes for the GCC inline assembler clobber lists. */
|
||||||
#define R_AtomJmp_Code R_T8_Code
|
#define R_ScratchBase_Code R_SP_Code
|
||||||
#define R_TapePtr_Code R_T9_Code
|
#define R_AtomJmp_Code R_FP_Code
|
||||||
|
#define R_TapePtr_Code R_RA_Code
|
||||||
|
|
||||||
// R_InCursor = R_T4,
|
// R_InCursor = R_T4,
|
||||||
// #define R_InCursor_Code R_T4_Code
|
// #define R_InCursor_Code R_T4_Code
|
||||||
|
|
||||||
// Reserved Registers (Callee-saved):
|
// Reserved Registers (Callee-saved across the host ABI transition):
|
||||||
// - R_T9: Holds the Tape Ptr which we need to increment
|
// - R_SP: Holds the scratchpad base while tape code executes.
|
||||||
// - R_RA: Return address register
|
// - R_FP: Holds the next atom target.
|
||||||
// Needed by ac_yield but can be used as atom scratch:
|
// - R_RA: Holds the tape cursor.
|
||||||
// - R_T8: Will be used as the atom jump register.
|
// All atom-body allocations must stay out of these.
|
||||||
|
// Atom bodies may freely use R2-R25.
|
||||||
|
|
||||||
// All allocatable registers for mips atoms:
|
// All allocatable registers for atom bodies (R2-R25, 24 registers):
|
||||||
|
|
||||||
// TODO(Ed): Make this the R_AtomJmp register since its better to clobber across atoms.
|
R_PsuedoVolatile = R_AT, // Assembler temporary; never allocate.
|
||||||
R_TScratchVolatile = R_AT, // This one is reserved for psuedo instructions, but you can technically use it.
|
|
||||||
|
|
||||||
R_TScratch0 = R_T0,
|
// Atom Allocation Pool
|
||||||
R_TScratch1 = R_T1,
|
R_Atom0 = R_T0,
|
||||||
R_TScratch2 = R_T2,
|
R_Atom1 = R_T1,
|
||||||
R_TScratch3 = R_T3,
|
R_Atom2 = R_T2,
|
||||||
R_TScratch4 = R_T4,
|
R_Atom3 = R_T3,
|
||||||
R_TScratch5 = R_T5,
|
R_Atom4 = R_T4,
|
||||||
R_TScratch6 = R_T6,
|
R_Atom5 = R_T5,
|
||||||
R_TScratch7 = R_T7,
|
R_Atom6 = R_T6,
|
||||||
R_TScratch8 = R_T8, // Clobbered by the yield on a per-atom boundary.
|
R_Atom7 = R_T7,
|
||||||
R_TScratch10 = R_V0, // Tend to be used with gte DMAs
|
R_Atom8 = R_T8,
|
||||||
R_TScratch11 = R_V1, // Tend to be used with gte DMAs
|
R_Atom9 = R_T9,
|
||||||
// Note(Ed): We can technically clobber these, but don't unless we hit a bottleneck.
|
R_Atom10 = R_V0, // Tend to be used with gte DMAs
|
||||||
// A 0-2
|
R_Atom11 = R_V1, // Tend to be used with gte DMAs
|
||||||
// S 0-7
|
R_Atom12 = R_A0,
|
||||||
|
R_Atom13 = R_A1,
|
||||||
|
R_Atom14 = R_A2,
|
||||||
|
R_Atom15 = R_A3,
|
||||||
|
R_Atom16 = R_S0,
|
||||||
|
R_Atom17 = R_S1,
|
||||||
|
R_Atom18 = R_S2,
|
||||||
|
R_Atom19 = R_S3,
|
||||||
|
R_Atom20 = R_S4,
|
||||||
|
R_Atom21 = R_S5,
|
||||||
|
R_Atom22 = R_S6,
|
||||||
|
R_Atom23 = R_S7,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef U2 Reg; // Register parameter used with atom or atom component procedures
|
typedef U2 Reg; // Register parameter used with atom or atom component procedures
|
||||||
@@ -110,6 +123,7 @@ typedef Slice_(MipsCode);
|
|||||||
|
|
||||||
typedef U4 const MipsAtom; // Underlying type to a mips atom defnition
|
typedef U4 const MipsAtom; // Underlying type to a mips atom defnition
|
||||||
typedef Slice_(MipsAtom);
|
typedef Slice_(MipsAtom);
|
||||||
|
|
||||||
// Sometimes a user will define a bundle of atoms that represent a procedure of work as:
|
// Sometimes a user will define a bundle of atoms that represent a procedure of work as:
|
||||||
// MipsAtom* <identifier>[...];
|
// MipsAtom* <identifier>[...];
|
||||||
// Unfortuantely if using slice_from_array it will make the slice's pointer: MipsAtom** so this enforce its defined as MipsAtom*
|
// Unfortuantely if using slice_from_array it will make the slice's pointer: MipsAtom** so this enforce its defined as MipsAtom*
|
||||||
@@ -153,53 +167,71 @@ typedef Slice_(MipsAtom);
|
|||||||
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.
|
||||||
Macro expands to a file-scope `internal U4 const` declaration keeps the file in the line table.
|
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.
|
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
|
#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 Slice_MipsAtom Tape;
|
||||||
|
|
||||||
/* The 'Exit' Atom */
|
typedef Struct_(TapeHostFrame) {
|
||||||
atom_dbg_skip MipsAtom_(tape_exit) { jump_reg(R_RA), nop };
|
U4 s0;
|
||||||
|
U4 s1;
|
||||||
|
U4 s2;
|
||||||
|
U4 s3;
|
||||||
|
U4 s4;
|
||||||
|
U4 s5;
|
||||||
|
U4 s6;
|
||||||
|
U4 s7;
|
||||||
|
U4 fp;
|
||||||
|
U4 sp;
|
||||||
|
U4 ra;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO(Ed): When we have a substantial workload/throughput, profile each of these to see impact at ABI boundaries.
|
enum {
|
||||||
|
TapeHostFrame_Loc = Scratchpad_End - S_(TapeHostFrame),
|
||||||
|
TapeScratch_Len = TapeHostFrame_Loc - Scratchpad_Loc,
|
||||||
|
};
|
||||||
|
static_assert(S_(TapeHostFrame) == 11 * S_(U4));
|
||||||
|
static_assert(TapeHostFrame_Loc == 0x1F8003D4);
|
||||||
|
|
||||||
/* Tape Runner (Default) */
|
atom_dbg_skip MipsAtom_(tape_enter) {
|
||||||
FI_ void tape_run(Tape tape) { register U4* tape_ptr rgcc(R_TapePtr) = u4_r(tape.ptr); asm volatile(
|
mac_load_word_imm(R_V0, u4_(TapeHostFrame_Loc)),
|
||||||
asm_words(
|
store_word(R_S0, R_V0, O_(TapeHostFrame,s0)),
|
||||||
load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
|
store_word(R_S1, R_V0, O_(TapeHostFrame,s1)),
|
||||||
, add_ui_self(R_TapePtr, S_(MipsAtom)) /* Advance tape */
|
store_word(R_S2, R_V0, O_(TapeHostFrame,s2)),
|
||||||
, call_reg( R_AtomJmp) /* jalr $t8 */
|
store_word(R_S3, R_V0, O_(TapeHostFrame,s3)),
|
||||||
, BdSlot_ nop /* Branch delay slot */
|
store_word(R_S4, R_V0, O_(TapeHostFrame,s4)),
|
||||||
)
|
store_word(R_S5, R_V0, O_(TapeHostFrame,s5)),
|
||||||
asm_rpins, r_use(tape_ptr)
|
store_word(R_S6, R_V0, O_(TapeHostFrame,s6)),
|
||||||
asm_clobber:
|
store_word(R_S7, R_V0, O_(TapeHostFrame,s7)),
|
||||||
rlit(R_AT),
|
store_word(R_FP, R_V0, O_(TapeHostFrame,fp)),
|
||||||
rlit(R_V0), rlit(R_V1), // We clobber these for GTE ACs (that don't expose register selection, might expose them in the future...)
|
store_word(R_SP, R_V0, O_(TapeHostFrame,sp)),
|
||||||
rlit(R_T0), rlit(R_T1), rlit(R_T2), rlit(R_T3), rlit(R_T4),
|
store_word(R_RA, R_V0, O_(TapeHostFrame,ra)),
|
||||||
rlit(R_T5), rlit(R_T6), rlit(R_T7), rlit(R_T8),
|
add_ui(R_TapePtr, R_A0, 0),
|
||||||
clb_mem_drain
|
load_upper_i(R_ScratchBase, u4_hi(Scratchpad_Loc)),
|
||||||
); }
|
load_word(R_AtomJmp, R_TapePtr, 0),
|
||||||
|
add_ui_self( R_TapePtr, S_(MipsAtom)),
|
||||||
|
jump_reg(R_AtomJmp), BdSlot_ nop,
|
||||||
|
};
|
||||||
|
|
||||||
/* Tape Runner (Static and Arg Clobbers) */
|
atom_dbg_skip MipsAtom_(tape_exit) {
|
||||||
FI_ void tape_run_a02_s07(Tape tape) { register U4* tape_ptr rgcc(R_TapePtr) = u4_r(tape.ptr); asm volatile(
|
mac_load_word_imm(R_V0, u4_(TapeHostFrame_Loc)),
|
||||||
asm_words(
|
load_word(R_S0, R_V0, O_(TapeHostFrame,s0)),
|
||||||
load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
|
load_word(R_S1, R_V0, O_(TapeHostFrame,s1)),
|
||||||
, add_ui_self(R_TapePtr, S_(MipsAtom)) /* Advance tape */
|
load_word(R_S2, R_V0, O_(TapeHostFrame,s2)),
|
||||||
, call_reg( R_AtomJmp) /* jalr $t8 */
|
load_word(R_S3, R_V0, O_(TapeHostFrame,s3)),
|
||||||
, BdSlot_ nop /* Branch delay slot */
|
load_word(R_S4, R_V0, O_(TapeHostFrame,s4)),
|
||||||
)
|
load_word(R_S5, R_V0, O_(TapeHostFrame,s5)),
|
||||||
asm_rpins, r_use(tape_ptr)
|
load_word(R_S6, R_V0, O_(TapeHostFrame,s6)),
|
||||||
asm_clobber:
|
load_word(R_S7, R_V0, O_(TapeHostFrame,s7)),
|
||||||
rlit(R_AT),
|
load_word(R_RA, R_V0, O_(TapeHostFrame,ra)),
|
||||||
rlit(R_V0), rlit(R_V1), rlit(R_A0), rlit(R_A1), rlit(R_A2),
|
load_word(R_FP, R_V0, O_(TapeHostFrame,fp)),
|
||||||
rlit(R_T0), rlit(R_T1), rlit(R_T2), rlit(R_T3), rlit(R_T4),
|
load_word(R_SP, R_V0, O_(TapeHostFrame,sp)),
|
||||||
rlit(R_T5), rlit(R_T6), rlit(R_T7), rlit(R_T8),
|
jump_reg(R_RA), BdSlot_ nop,
|
||||||
rlit(R_S0), rlit(R_S1), rlit(R_S2), rlit(R_S3), rlit(R_S4),
|
};
|
||||||
rlit(R_S5), rlit(R_S6), rlit(R_S7),
|
|
||||||
clb_mem_drain
|
typedef void Proc_(TapeEntryFn)(MipsAtom* tape_ptr);
|
||||||
); }
|
|
||||||
|
FI_ void tape_run(Tape tape) { C_(TapeEntryFn*, tape_enter)(tape.ptr); }
|
||||||
|
|
||||||
// Procedural authoring of tapes:
|
// Procedural authoring of tapes:
|
||||||
typedef Relative_(FArena) Struct_(TapeBuilder) { U4 ptr; U4 capacity; U4 used; };
|
typedef Relative_(FArena) Struct_(TapeBuilder) { U4 ptr; U4 capacity; U4 used; };
|
||||||
@@ -242,18 +274,13 @@ atom_dbg_skip MipsAtomComp_(ac_yield_load) {
|
|||||||
|
|
||||||
atom_dbg_skip MipsAtomComp_(ac_yield_tail) {
|
atom_dbg_skip MipsAtomComp_(ac_yield_tail) {
|
||||||
add_ui_self(R_TapePtr, S_(MipsCode)),
|
add_ui_self(R_TapePtr, S_(MipsCode)),
|
||||||
jump_reg( R_AtomJmp),
|
jump_reg( R_AtomJmp), BdSlot_ nop,
|
||||||
BdSlot_ nop,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma endregion Macro Atom Components
|
#pragma endregion Macro Atom Components
|
||||||
|
|
||||||
#pragma region Atom Builder
|
#pragma region Atom Builder
|
||||||
// This helps with runtime procedural authoring of mips atoms.
|
// This helps with runtime procedural authoring of mips atoms.
|
||||||
|
|
||||||
typedef Struct_(FMipsAtom512) { U4 data[512]; U4 used; };
|
|
||||||
|
|
||||||
// FArena Related
|
|
||||||
typedef Relative_(FArena) Struct_(AtomBuilder) { U4 start; U4 capacity; U4 used; };
|
typedef Relative_(FArena) Struct_(AtomBuilder) { U4 start; U4 capacity; U4 used; };
|
||||||
|
|
||||||
// Usual way to resolve an atom after the bulder is done.
|
// Usual way to resolve an atom after the bulder is done.
|
||||||
@@ -274,7 +301,6 @@ FI_ void tb_emit_atombuilder(TapeBuilder_R tb, AtomBuilder_R ab) { tb_emit(tb, a
|
|||||||
|
|
||||||
#pragma region Atom Arena
|
#pragma region Atom Arena
|
||||||
// Just a dedicated FArena that is meant to mem_copy and return atom definitions made with MipsAtom_Proc_
|
// Just a dedicated FArena that is meant to mem_copy and return atom definitions made with MipsAtom_Proc_
|
||||||
|
|
||||||
typedef Relative_(FArena) Struct_(AtomArena) { U4 start; U4 capacity; U4 used; };
|
typedef Relative_(FArena) Struct_(AtomArena) { U4 start; U4 capacity; U4 used; };
|
||||||
|
|
||||||
#define atomarena_unused_start(ab) ((ab).start + (ab).used)
|
#define atomarena_unused_start(ab) ((ab).start + (ab).used)
|
||||||
@@ -299,13 +325,24 @@ FI_ void atomarena_reset(AtomArena_R aa) { aa->used = 0; }
|
|||||||
// TODO(Ed): Technically we can do this at comp-time with the metaprogram, but we may have namespace conflicts.
|
// 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.
|
// Unless we follow a convention for #define <Scope_Prefix> or something per register allocation boundary.
|
||||||
|
|
||||||
/* ABI + tape reserves that are never handed out by alloc. */
|
/* ABI reserves that are never handed out by alloc.
|
||||||
|
* R_AT is the assembler temporary (per the MIPS O32 ABI).
|
||||||
|
* R_K0/K1 are kernel reserves.
|
||||||
|
* R_GP stays the host global pointer.
|
||||||
|
* R_SP/R_FP/R_RA are tape runtime carriers between tape_enter and tape_exit. */
|
||||||
U4 const regfile_abi_mask =
|
U4 const regfile_abi_mask =
|
||||||
(1u << R_0) | (1u << R_AT) |
|
(1u << R_0) | (1u << R_AT) |
|
||||||
(1u << R_K0) | (1u << R_K1) |
|
(1u << R_K0) | (1u << R_K1) |
|
||||||
(1u << R_GP) | (1u << R_SP) |
|
(1u << R_GP) | (1u << R_SP) |
|
||||||
(1u << R_FP) | (1u << R_RA) |
|
(1u << R_FP) | (1u << R_RA);
|
||||||
(1u << R_T8) | (1u << R_T9); /* AtomJmp + TapePtr */
|
|
||||||
|
internal Reg const regfile_alloc_order[] = {
|
||||||
|
R_V0, R_V1,
|
||||||
|
R_A0, R_A1, R_A2, R_A3,
|
||||||
|
R_T0, R_T1, R_T2, R_T3, R_T4, R_T5, R_T6, R_T7,
|
||||||
|
R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7,
|
||||||
|
R_T8, R_T9,
|
||||||
|
};
|
||||||
|
|
||||||
typedef Struct_(RegFile) {
|
typedef Struct_(RegFile) {
|
||||||
A2_U2 GPR;
|
A2_U2 GPR;
|
||||||
@@ -340,13 +377,16 @@ 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) {
|
||||||
U2 allocated = 0;
|
Reg allocated = 0;
|
||||||
for index_iter(Reg, r_id, R_T0, <=, R_T7) {
|
for index_iter(U4, idx, 0, <, Array_len(regfile_alloc_order)) {
|
||||||
allocated = regfile__alloc_helper(rf->GPR, r_id); Jmp_nZero_(allocated,resolved);
|
allocated = regfile__alloc_helper(rf->GPR, idx);
|
||||||
|
Jmp_nZero_(allocated,resolved);
|
||||||
}
|
}
|
||||||
allocated = regfile__alloc_helper(rf->GPR, R_V0); Jmp_nZero_(allocated,resolved);
|
|
||||||
allocated = regfile__alloc_helper(rf->GPR, R_V1);
|
|
||||||
assert(allocated != 0);
|
assert(allocated != 0);
|
||||||
resolved: return allocated;
|
resolved: return allocated;
|
||||||
}
|
}
|
||||||
@@ -383,9 +423,7 @@ FI_ void regfile_reset_to_mask(RegFile_R rf, U4 mask) {
|
|||||||
|
|
||||||
#pragma region Mips Atom Procs
|
#pragma region Mips Atom Procs
|
||||||
/* RegUse structs are a convention to organize register allocations for a mips atom procedure.
|
/* RegUse structs are a convention to organize register allocations for a mips atom procedure.
|
||||||
Unlike the usual enum-based declarations, they provide a namespaced scope
|
Unlike the usual enum-based declarations, they provide a namespaced scope and have view types via union declarations. */
|
||||||
and have view types via union declarations.
|
|
||||||
*/
|
|
||||||
#define RegUse_(proc_name) (tmpl(RegUse,proc_name))
|
#define RegUse_(proc_name) (tmpl(RegUse,proc_name))
|
||||||
|
|
||||||
typedef Struct_(RegUse_example_atom_proc) {
|
typedef Struct_(RegUse_example_atom_proc) {
|
||||||
|
|||||||
@@ -134,10 +134,12 @@ FI_ U4 farena_unused_start(FArena arena) { return arena.start + arena.used; }
|
|||||||
|
|
||||||
#pragma region BIOS Scratchpad
|
#pragma region BIOS Scratchpad
|
||||||
/* BIOS scratchpad location. 1 KB at 0x1F800000.
|
/* BIOS scratchpad location. 1 KB at 0x1F800000.
|
||||||
* The PS1 BIOS A-functions use this region for inter-call communication and as a temp storage area.
|
* TapeHostFrame occupies the final 44 bytes while tape code executes.
|
||||||
* The Tape runtime uses scratch region along with explicit data structures instead of the stack-based scratch from the C-Runtime. */
|
* Atom scratch is bounded by the TapeHostFrame_Loc declaration in lottes_tape.h. */
|
||||||
enum {
|
enum {
|
||||||
Scratchpad_Loc = 0x1F800000,
|
Scratchpad_Loc = 0x1F800000,
|
||||||
|
Scratchpad_Len = 0x400, /* 1 KB */
|
||||||
|
Scratchpad_End = Scratchpad_Loc + Scratchpad_Len, /* 0x1F800400 */
|
||||||
};
|
};
|
||||||
#define C_scratch(type) C_(type, Scratchpad_Loc)
|
#define C_scratch(type) C_(type, Scratchpad_Loc)
|
||||||
#pragma endregion BIOS Scratchpad
|
#pragma endregion BIOS Scratchpad
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(pad_atom_c);
|
|||||||
|
|
||||||
FI_ Slice_MipsCode ac_pad_set_centered_axes(AtomBuilder_R ab, Reg state, Reg scratch) atom_dbg_skip MipsAtomComp_Proc_(ab, {
|
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),
|
load_upper_i(scratch, (PadAxis_Centered >> 16) & 0xFFFF),
|
||||||
or_i_self( scratch, PadAxis_Centered & 0xFFFF),
|
or_i_self( scratch, PadAxis_Centered & 0xFFFF), // mac_load_word_imm(scratch, PadAxis_Centered),
|
||||||
// mac_load_word_imm(scratch, PadAxis_Centered),
|
|
||||||
store_word( scratch, state, O_(PadState,axes)),
|
store_word( scratch, state, O_(PadState,axes)),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -101,14 +101,14 @@ MipsAtomComp_Proc_(ab, {
|
|||||||
#pragma region resolve_look_at
|
#pragma region resolve_look_at
|
||||||
/* ─── resolve_look_at bundle chain atoms ──────────────────────────── */
|
/* ─── resolve_look_at bundle chain atoms ──────────────────────────── */
|
||||||
|
|
||||||
typedef AtomBundle_(resolve_look_at) { MipsAtom*
|
typedef AtomBundle_(resolve_look_at) { MipsAtom
|
||||||
input_and_sub,
|
*input_and_sub,
|
||||||
normalize_fwd_uz,
|
*normalize_fwd_uz,
|
||||||
cross_to_right,
|
*cross_to_right,
|
||||||
normalize_right_ux,
|
*normalize_right_ux,
|
||||||
cross_to_up,
|
*cross_to_up,
|
||||||
normalize_up_uy,
|
*normalize_up_uy,
|
||||||
pop_mv_trans;
|
*pop_mv_trans;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
#pragma endregion Hello Joypad TUs
|
#pragma endregion Hello Joypad TUs
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Scratchpad_Len = 1024,
|
|
||||||
MemTape_Len = 512,
|
MemTape_Len = 512,
|
||||||
|
|
||||||
ResolveLookAtArena_Words = 1024,
|
ResolveLookAtArena_Words = 1024,
|
||||||
@@ -86,11 +85,7 @@ typedef Struct_(SMemory) {
|
|||||||
|
|
||||||
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; /* GTE OP OuterProduct12 (a × b → out).
|
MipsAtom* gte_cross_v3s4;
|
||||||
* Baked once at init from compile_gte_cross_v3s4() into ct_init_atom_mem.
|
|
||||||
* One instance serves both cross call sites in resolve_look_at;
|
|
||||||
* per-frame tape emits push src_a/src_b/out (3 pointers = 12 bytes)
|
|
||||||
* for Binds_gte_cross_v3s4. */
|
|
||||||
|
|
||||||
U1 resolve_look_at_mem[ResolveLookAtArena_Size];
|
U1 resolve_look_at_mem[ResolveLookAtArena_Size];
|
||||||
MipsAtom* resolve_look_at_bundle[AtomBundle_Len(resolve_look_at)];
|
MipsAtom* resolve_look_at_bundle[AtomBundle_Len(resolve_look_at)];
|
||||||
@@ -138,70 +133,52 @@ I_ void resolve_look_at_c11(MT3_S2S4* look_at, P3_S4* eye, P3_S4* target, V3_S4*
|
|||||||
}
|
}
|
||||||
FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at_c11(& c->look_at, & c->pos, target, up_in); }
|
FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at_c11(& c->look_at, & c->pos, target, up_in); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal void compile_init_atoms(void) {
|
internal void compile_init_atoms(void) {
|
||||||
/* Single shared arena: each compile_* function pushes its atom into the same
|
|
||||||
* ct_init_atom_mem backing. If each function called atomarena_make() locally,
|
|
||||||
* the second call would reset arena.used to 0 and overwrite the first atom.
|
|
||||||
*/
|
|
||||||
AtomArena ab = atomarena_make(slice_ut_arr(smem.ct_init_atom_mem));
|
AtomArena ab = atomarena_make(slice_ut_arr(smem.ct_init_atom_mem));
|
||||||
RegFile rf = regfile(regfile_abi_mask);
|
RegFile rf = regfile(regfile_abi_mask);
|
||||||
|
#define ralloc() regfile_alloc(& rf)
|
||||||
|
#define ralloc_v3() { ralloc(), ralloc(), ralloc() }
|
||||||
|
|
||||||
/* === gte_cross_v3s4 — GTE OP OuterProduct12 (a × b → out) ===
|
|
||||||
* Reused by both cross call sites in resolve_look_at. No scratch carrier.
|
|
||||||
* GPR pool: 9 allocatable (no carrier). Pool R_T0..R_T7, R_V0, R_V1 minus ABI = 9.
|
|
||||||
* Fits exactly. */
|
|
||||||
{
|
|
||||||
smem.gte_cross_v3s4 = gte_cross_v3s4(& ab,
|
smem.gte_cross_v3s4 = gte_cross_v3s4(& ab,
|
||||||
RegUse_(gte_cross_v3s4) {
|
RegUse_(gte_cross_v3s4) {
|
||||||
.a = { regfile_alloc(& rf), regfile_alloc(& rf), regfile_alloc(& rf) },
|
.a = ralloc_v3(),
|
||||||
.b = { regfile_alloc(& rf), regfile_alloc(& rf), regfile_alloc(& rf) },
|
.b = ralloc_v3(),
|
||||||
.x = regfile_alloc(& rf), /* out / t0 shared */
|
.x = ralloc(),
|
||||||
.y = regfile_alloc(& rf), /* src_a / t1 / rt11 shared */
|
.y = ralloc(),
|
||||||
.z = regfile_alloc(& rf), /* src_b / t2 / rt22 shared */
|
.z = ralloc(),
|
||||||
});
|
});
|
||||||
regfile_reset(& rf);
|
regfile_reset(& rf);
|
||||||
}
|
|
||||||
|
|
||||||
/* === build_normalize_v3s4 — Generic 4-stage GTE normalize ===
|
|
||||||
* Reused by all 3 normalize call sites in resolve_look_at. Reads scratch + src/dst
|
|
||||||
* offsets from tape (no carrier — atom is fully self-contained per call).
|
|
||||||
* GPR pool: no carrier, 10 allocatable (R_T0..R_T7, R_V0, R_V1 minus ABI pins).
|
|
||||||
* 10 fields (scratch + src_ptr + dst_ptr + recip_est + norm + shift + src_x +
|
|
||||||
* t3 + t4 + t5) → just fits. Union members t5.src_offset, t3.dst_offset, etc.
|
|
||||||
* share GPRs via lifetime discipline. */
|
|
||||||
{
|
|
||||||
RegFile rf = regfile(regfile_abi_mask);
|
|
||||||
smem.normalize_v3s4 = build_normalize_v3s4(& ab,
|
smem.normalize_v3s4 = build_normalize_v3s4(& ab,
|
||||||
RegUse_(build_normalize_v3s4) {
|
RegUse_(build_normalize_v3s4) {
|
||||||
.scratch = regfile_alloc(& rf),
|
.scratch = ralloc(),
|
||||||
.src_ptr = regfile_alloc(& rf),
|
.src_ptr = ralloc(),
|
||||||
.dst_ptr = regfile_alloc(& rf),
|
.dst_ptr = ralloc(),
|
||||||
.recip_est = regfile_alloc(& rf),
|
.recip_est = ralloc(),
|
||||||
.norm = regfile_alloc(& rf),
|
.norm = ralloc(),
|
||||||
.shift = regfile_alloc(& rf),
|
.shift = ralloc(),
|
||||||
.src_x = regfile_alloc(& rf),
|
.src_x = ralloc(),
|
||||||
.t3 = regfile_alloc(& rf),
|
.t3 = ralloc(),
|
||||||
.t4 = regfile_alloc(& rf),
|
.t4 = ralloc(),
|
||||||
.t5 = regfile_alloc(& rf),
|
.t5 = ralloc(),
|
||||||
});
|
});
|
||||||
}
|
regfile_reset(& rf);
|
||||||
|
|
||||||
assert(ab.used <= CT_InitAtomMem_Size);
|
assert(ab.used <= CT_InitAtomMem_Size);
|
||||||
|
#undef ralloc
|
||||||
|
#undef ralloc_v3
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void compile_resolve_look_at(void) {
|
internal void compile_resolve_look_at(void) {
|
||||||
/* Wrap the static arena in a MipsAtomBuilder. */
|
|
||||||
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
|
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem));
|
||||||
TapeBuilder tb = tb_make(slice_ut_arr(smem.resolve_look_at_bundle));
|
AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
|
||||||
|
|
||||||
U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch);
|
U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch);
|
||||||
RegFile rf = regfile(pin_mask);
|
RegFile rf = regfile(pin_mask);
|
||||||
#define ralloc() regfile_alloc(& rf)
|
#define ralloc() regfile_alloc(& rf)
|
||||||
#define ralloc_v3() { ralloc(), ralloc(), ralloc() }
|
#define ralloc_v3() { ralloc(), ralloc(), ralloc() }
|
||||||
|
|
||||||
tb_emit_(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) {
|
||||||
.scratch = R_ResolveScratch,
|
.scratch = R_ResolveScratch,
|
||||||
.target = ralloc(),
|
.target = ralloc(),
|
||||||
@@ -212,37 +189,25 @@ internal void compile_resolve_look_at(void) {
|
|||||||
.t2 = ralloc(),
|
.t2 = ralloc(),
|
||||||
.t3 = ralloc(),
|
.t3 = ralloc(),
|
||||||
.t4 = ralloc(),
|
.t4 = ralloc(),
|
||||||
}
|
});
|
||||||
));
|
|
||||||
regfile_reset_to_mask(& rf, pin_mask);
|
regfile_reset_to_mask(& rf, pin_mask);
|
||||||
|
|
||||||
/* === ATOM 1: normalize fwd→uz === */
|
bundle->normalize_fwd_uz = smem.normalize_v3s4;
|
||||||
smem.resolve_look_at_bundle[1] = smem.normalize_v3s4;
|
bundle->cross_to_right = smem.gte_cross_v3s4;
|
||||||
|
bundle->normalize_right_ux = smem.normalize_v3s4;
|
||||||
|
bundle->cross_to_up = smem.gte_cross_v3s4;
|
||||||
|
bundle->normalize_up_uy = smem.normalize_v3s4;
|
||||||
|
|
||||||
/* === ATOM 2: cross uz×up_in→right (reuses smem.gte_cross_v3s4) === */
|
bundle->pop_mv_trans = resolve_look_at__pop_mv_trans(& ab,
|
||||||
smem.resolve_look_at_bundle[2] = smem.gte_cross_v3s4;
|
|
||||||
|
|
||||||
/* === ATOM 3: normalize right→ux === */
|
|
||||||
smem.resolve_look_at_bundle[3] = smem.normalize_v3s4;
|
|
||||||
|
|
||||||
/* === ATOM 4: cross uz×ux→up (reuses smem.gte_cross_v3s4) === */
|
|
||||||
smem.resolve_look_at_bundle[4] = smem.gte_cross_v3s4;
|
|
||||||
|
|
||||||
/* === ATOM 5: normalize up→uy === */
|
|
||||||
smem.resolve_look_at_bundle[5] = smem.normalize_v3s4;
|
|
||||||
|
|
||||||
/* === ATOM 6 (FUSED): populate + ctc2 RT + MVMVA + trans_matrix → look_at === */
|
|
||||||
smem.resolve_look_at_bundle[6] = resolve_look_at__pop_mv_trans(& ab,
|
|
||||||
RegUse_(resolve_look_at__pop_mv_trans){
|
RegUse_(resolve_look_at__pop_mv_trans){
|
||||||
.scratch = R_ResolveScratch,
|
.scratch = R_ResolveScratch,
|
||||||
.look_at = ralloc(), /* T0 */
|
.look_at = ralloc(),
|
||||||
.eye = ralloc(), /* T1 — allocated BEFORE row so it doesn't alias row.y */
|
.eye = ralloc(),
|
||||||
.row = ralloc_v3(), /* T2 T3 T5 */
|
.row = ralloc_v3(),
|
||||||
.t6 = ralloc(), /* T6 = ux (populate) / v_x (matrix_vector) */
|
.t6 = ralloc(),
|
||||||
.t7 = ralloc(), /* T7 = uy (populate) / v_y (matrix_vector) */
|
.t7 = ralloc(),
|
||||||
.t8 = ralloc(), /* V0 = uz (populate) / v_z (matrix_vector) */
|
.t8 = ralloc(),
|
||||||
});
|
});
|
||||||
/* No regfile_reset between phases: the fused atom uses all 9 GPRs throughout. */
|
|
||||||
|
|
||||||
/* Sanity check: arena didn't overflow. */
|
/* Sanity check: arena didn't overflow. */
|
||||||
assert(ab.used <= ResolveLookAtArena_Size);
|
assert(ab.used <= ResolveLookAtArena_Size);
|
||||||
@@ -258,42 +223,34 @@ I_ void resolve_look_at(TapeBuilder_R tb
|
|||||||
){
|
){
|
||||||
/* 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);
|
||||||
|
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[0]); {
|
tb_emit(tb, bundle->input_and_sub); {
|
||||||
tb_data(tb, u4_(target));
|
tb_data(tb, u4_(target));
|
||||||
tb_data(tb, u4_(eye));
|
tb_data(tb, u4_(eye));
|
||||||
tb_data(tb, u4_(up_in));
|
tb_data(tb, u4_(up_in));
|
||||||
tb_data(tb, u4_(smem.scratchpad));
|
tb_data(tb, u4_(smem.scratchpad));
|
||||||
}
|
}
|
||||||
|
tb_emit(tb, bundle->normalize_fwd_uz); {
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[1]); {
|
|
||||||
/* Binds_NormalizeV3S4: src_offset (low 16) | dst_offset (high 16). Both U2s
|
|
||||||
* packed into a single U4 because the atom body reads at byte offsets 0 and 2
|
|
||||||
* from R_TapePtr. Scratch base is baked into the atom (load_word_imm of
|
|
||||||
* Scratchpad_Loc). */
|
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16)));
|
tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16)));
|
||||||
}
|
}
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[2]); {
|
tb_emit(tb, bundle->cross_to_right); {
|
||||||
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
|
tb_data(tb, u4_(& sp->uz));
|
||||||
tb_data(tb, u4_(& sp->uz)); /* src_a */
|
tb_data(tb, u4_(& sp->up_in));
|
||||||
tb_data(tb, u4_(& sp->up_in)); /* src_b */
|
tb_data(tb, u4_(& sp->right));
|
||||||
tb_data(tb, u4_(& sp->right)); /* out */
|
|
||||||
}
|
}
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[3]); {
|
tb_emit(tb, bundle->normalize_right_ux); {
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, right) | (O_(ResolveLookAtScratch, ux) << 16)));
|
tb_data(tb, u4_(O_(ResolveLookAtScratch, right) | (O_(ResolveLookAtScratch, ux) << 16)));
|
||||||
}
|
}
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[4]); {
|
tb_emit(tb, bundle->cross_to_up); {
|
||||||
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
|
tb_data(tb, u4_(& sp->uz));
|
||||||
tb_data(tb, u4_(& sp->uz)); /* src_a */
|
tb_data(tb, u4_(& sp->ux));
|
||||||
tb_data(tb, u4_(& sp->ux)); /* src_b */
|
tb_data(tb, u4_(& sp->up));
|
||||||
tb_data(tb, u4_(& sp->up)); /* out */
|
|
||||||
}
|
}
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[5]); {
|
tb_emit(tb, bundle->normalize_up_uy); {
|
||||||
tb_data(tb, u4_(O_(ResolveLookAtScratch, up) | (O_(ResolveLookAtScratch, uy) << 16)));
|
tb_data(tb, u4_(O_(ResolveLookAtScratch, up) | (O_(ResolveLookAtScratch, uy) << 16)));
|
||||||
}
|
}
|
||||||
|
tb_emit(tb, bundle->pop_mv_trans); {
|
||||||
/* === FUSED atom: populate + matrix_vector + trans_matrix (replaces 4 separate emits) === */
|
|
||||||
tb_emit(tb, smem.resolve_look_at_bundle[6]); {
|
|
||||||
tb_data(tb, u4_(look_at));
|
tb_data(tb, u4_(look_at));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,12 +290,6 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
gknown V3_S4_R acc = & smem.cube.accel;
|
gknown V3_S4_R acc = & smem.cube.accel;
|
||||||
add_v3s4(vel, acc[0]);
|
add_v3s4(vel, acc[0]);
|
||||||
add_v3s4_fp(pos, vel[0]);
|
add_v3s4_fp(pos, vel[0]);
|
||||||
// vel->x += acc->x;
|
|
||||||
// vel->y += acc->y;
|
|
||||||
// vel->z += acc->z;
|
|
||||||
// pos->x += vel->x;
|
|
||||||
// pos->y += vel->y;
|
|
||||||
// pos->z += vel->z;
|
|
||||||
|
|
||||||
if (pos->y + 150 > smem.floor.pos.y) vel->y *= -1;
|
if (pos->y + 150 > smem.floor.pos.y) vel->y *= -1;
|
||||||
|
|
||||||
@@ -371,9 +322,6 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
gte_matrix_set_rotation (& smem.tform_view);
|
gte_matrix_set_rotation (& smem.tform_view);
|
||||||
gte_matrix_set_translation(& smem.tform_view);
|
gte_matrix_set_translation(& smem.tform_view);
|
||||||
|
|
||||||
// gte_matrix_set_rotation (& smem.tform_world);
|
|
||||||
// gte_matrix_set_translation(& smem.tform_world);
|
|
||||||
|
|
||||||
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
|
U4 prim_base = u4_(pa->buf[smem.active_buf_id]);
|
||||||
U4 prim_cursor = prim_base + pa->used;
|
U4 prim_cursor = prim_base + pa->used;
|
||||||
|
|
||||||
@@ -393,7 +341,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
tb_data(& tb, u4_(& pa->used));
|
tb_data(& tb, u4_(& pa->used));
|
||||||
tb_data(& tb, prim_base);
|
tb_data(& tb, prim_base);
|
||||||
}
|
}
|
||||||
tape_run_a02_s07(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
|
tape_run(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
|
||||||
|
|
||||||
// smem.cube.rot.y += 30;
|
// smem.cube.rot.y += 30;
|
||||||
}
|
}
|
||||||
@@ -435,7 +383,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
|||||||
tb_data(& tb, u4_(& pa->used));
|
tb_data(& tb, u4_(& pa->used));
|
||||||
tb_data(& tb, prim_base);
|
tb_data(& tb, prim_base);
|
||||||
}
|
}
|
||||||
tape_run_a02_s07(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
|
tape_run(tb_slice(tb));// Fire off the tape (bigger-clobber variant).
|
||||||
|
|
||||||
// C-side state (pa->used) has already been updated by the tape!
|
// C-side state (pa->used) has already been updated by the tape!
|
||||||
// smem.floor.rot.y += 5;
|
// smem.floor.rot.y += 5;
|
||||||
|
|||||||
+7
-10
@@ -775,18 +775,16 @@ end
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- find_function_decl_for — backward walk for MipsAtomComp_Proc_ name extraction.
|
-- find_function_decl_for — backward walk for MipsAtomComp_Proc_ name extraction.
|
||||||
--
|
--
|
||||||
-- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name
|
-- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name is derived from the preceding
|
||||||
-- is derived from the preceding `FI_ Slice_MipsCode ac_X(args)` function
|
-- `FI_ Slice_MipsCode ac_X(args)` function declaration. This function walks backward from `before_pos` to find it.
|
||||||
-- declaration. This function walks backward from `before_pos` to find it.
|
|
||||||
--
|
--
|
||||||
-- Returns (raw_name, args_inner) or (nil, nil).
|
-- Returns (raw_name, args_inner) or (nil, nil).
|
||||||
-- raw_name — e.g. "ac_load_word_imm"
|
-- raw_name — e.g. "ac_load_word_imm"
|
||||||
-- args_inner — e.g. "AtomBuilder_R ab, Reg dst, U4 imm"
|
-- args_inner — e.g. "AtomBuilder_R ab, Reg dst, U4 imm"
|
||||||
--
|
--
|
||||||
-- The walk finds the LAST "Slice_MipsCode" before before_pos, then skips
|
-- The walk finds the LAST "Slice_MipsCode" before before_pos, then skips whitespace + qualifiers
|
||||||
-- whitespace + qualifiers (FI_, atom_dbg_skip, comments) until it finds an
|
-- (FI_, atom_dbg_skip, comments) until it finds an ident followed by "(".
|
||||||
-- ident followed by "(". That ident is the function name; the parens contents
|
-- That ident is the function name; the parens contents are the args.
|
||||||
-- are the args.
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
function M.find_function_decl_for(source, before_pos, slice_mips_code_len)
|
function M.find_function_decl_for(source, before_pos, slice_mips_code_len)
|
||||||
local search_pos = 1
|
local search_pos = 1
|
||||||
@@ -853,9 +851,8 @@ end
|
|||||||
-- args_inner — e.g. "AtomArena_R aa, U4 r_scratch, ..."
|
-- args_inner — e.g. "AtomArena_R aa, U4 r_scratch, ..."
|
||||||
-- after_paren — source position after the function `)`
|
-- after_paren — source position after the function `)`
|
||||||
--
|
--
|
||||||
-- The walk finds the LAST "MipsAtom*" before before_pos, then skips
|
-- The walk finds the LAST "MipsAtom*" before before_pos, then skips whitespace + qualifiers (internal, I_, FI_, comments)
|
||||||
-- whitespace + qualifiers (internal, I_, FI_, comments) until it finds an
|
-- until it finds an ident followed by "(".
|
||||||
-- ident followed by "(". That ident is the name. The parens contents are the args.
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len)
|
function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len)
|
||||||
local search_pos = 1
|
local search_pos = 1
|
||||||
|
|||||||
+205
-1095
File diff suppressed because it is too large
Load Diff
@@ -22,12 +22,10 @@ local M = {}
|
|||||||
local CACHE_KEY = "__duffle_repo_root__"
|
local CACHE_KEY = "__duffle_repo_root__"
|
||||||
|
|
||||||
--- Resolve the repo root from this script's own path. Zero shell spawn.
|
--- Resolve the repo root from this script's own path. Zero shell spawn.
|
||||||
--- `duffle_paths.lua` always lives at `<repo>/scripts/duffle_paths.lua`, so the repo root is the
|
--- `duffle_paths.lua` always lives at `<repo>/scripts/duffle_paths.lua`, so the repo root is the parent of the directory containing this script.
|
||||||
--- parent of the directory containing this script. We derive it directly from `debug.getinfo(1, "S").source`
|
--- We derive it directly from `debug.getinfo(1, "S").source` (returns `@<path>` for the currently-running chunk).
|
||||||
--- (returns `@<path>` for the currently-running chunk).
|
|
||||||
---
|
---
|
||||||
--- If `debug.getinfo` can't parse this script's path (shouldn't happen — dofile always populates source),
|
--- If `debug.getinfo` can't parse this script's path (shouldn't happen — dofile always populates source), return nil and let `M.setup()` fail loud.
|
||||||
--- return nil and let `M.setup()` fail loud.
|
|
||||||
--- @return string|nil
|
--- @return string|nil
|
||||||
local function find_repo_root()
|
local function find_repo_root()
|
||||||
if package.loaded[CACHE_KEY] then return package.loaded[CACHE_KEY] end
|
if package.loaded[CACHE_KEY] then return package.loaded[CACHE_KEY] end
|
||||||
@@ -51,17 +49,13 @@ end
|
|||||||
---
|
---
|
||||||
--- This script does NOT touch the OS environment: no `os.setenv`, no `os.putenv`, no `$PATH` mods.
|
--- This script does NOT touch the OS environment: no `os.setenv`, no `os.putenv`, no `$PATH` mods.
|
||||||
--- It just sets `package.path` and `package.cpath` (the standard Lua way to register module search dirs).
|
--- It just sets `package.path` and `package.cpath` (the standard Lua way to register module search dirs).
|
||||||
--- lpeg is built by `update_deps.ps1` to `toolchain/lpeg/`,
|
--- lpeg is built by `update_deps.ps1` to `toolchain/lpeg/`, which we wire into `package.cpath` here (so `require("lpeg")` from `duffle.lua` resolves without any global state).
|
||||||
--- which we wire into `package.cpath` here (so `require("lpeg")` from `duffle.lua` resolves without any global state).
|
|
||||||
function M.setup()
|
function M.setup()
|
||||||
local repo_root = find_repo_root()
|
local repo_root = find_repo_root()
|
||||||
if not repo_root then
|
if not repo_root then
|
||||||
-- Unreachable in practice: find_repo_root() derives the repo root from this script's
|
-- Unreachable in practice: find_repo_root() derives the repo root from this script's own source path via debug.getinfo(1, "S").source (no subprocess, no git CLI, <1ms).
|
||||||
-- own source path via debug.getinfo(1, "S").source (no subprocess, no git CLI, <1ms).
|
-- A nil return means the source path did not match the expected <repo>/scripts/duffle_paths.lua layout — a packaging bug, not a "missing git repo" condition.
|
||||||
-- A nil return means the source path did not match the expected
|
-- os.exit(2) is retained so a real failure surfaces loud rather than silently producing an unconfigured module table.
|
||||||
-- <repo>/scripts/duffle_paths.lua layout — a packaging bug, not a "missing git repo"
|
|
||||||
-- condition. os.exit(2) is retained so a real failure surfaces loud rather than
|
|
||||||
-- silently producing an unconfigured module table.
|
|
||||||
os.exit(2)
|
os.exit(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -86,6 +80,6 @@ end
|
|||||||
-- Run the setup as a side effect.
|
-- Run the setup as a side effect.
|
||||||
M.setup()
|
M.setup()
|
||||||
|
|
||||||
-- Now that package.path includes scripts/, `require("duffle")` resolves. Return the duffle module
|
-- Now that package.path includes scripts/, `require("duffle")` resolves.
|
||||||
-- so callers can do `local duffle = dofile(...duffle_paths.lua)` in one line.
|
-- Return the duffle module so callers can do `local duffle = dofile(...duffle_paths.lua)` in one line.
|
||||||
return require("duffle")
|
return require("duffle")
|
||||||
|
|||||||
@@ -468,8 +468,7 @@ function M.find_type_unit_by_signature(info, target_sig_lo, target_sig_hi)
|
|||||||
-- 20: <children>
|
-- 20: <children>
|
||||||
if body_end - body_start >= 20 then
|
if body_end - body_start >= 20 then
|
||||||
-- read_ref_sig8 / write_u32_le / etc. are 1-indexed (string:byte);
|
-- read_ref_sig8 / write_u32_le / etc. are 1-indexed (string:byte);
|
||||||
-- pos / body_start / body_end are 0-based wire offsets, so the
|
-- pos / body_start / body_end are 0-based wire offsets, so the 1-indexed byte at 0-based wire offset X is string:byte(X + 1).
|
||||||
-- 1-indexed byte at 0-based wire offset X is string:byte(X + 1).
|
|
||||||
-- Per DWARF5 §7.5.6, the type_unit body is laid out as:
|
-- Per DWARF5 §7.5.6, the type_unit body is laid out as:
|
||||||
-- byte 0-1: version (2)
|
-- byte 0-1: version (2)
|
||||||
-- byte 2: unit_type (1) -- DW_UT_type = 0x02
|
-- byte 2: unit_type (1) -- DW_UT_type = 0x02
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# scripts/launch_pcsx_debug.ps1
|
# scripts/launch_pcsx_debug.ps1
|
||||||
#
|
#
|
||||||
# One-shot launcher for debug sessions: starts pcsx-redux with the .ps-exe
|
# One-shot launcher for debug sessions:
|
||||||
# loaded, the gdb stub enabled, AND the pcsx_debug_helper Lua plugin loaded
|
# Starts pcsx-redux with the .ps-exe loaded, the gdb stub enabled,
|
||||||
# so external CLI tools (gdb's `shell` command, etc.)
|
# AND the pcsx_debug_helper Lua plugin loaded so external CLI tools (gdb's `shell` command, etc.)
|
||||||
# can read GTE state via http://localhost:8080/api/v1/lua/gte
|
# can read GTE state via http://localhost:8080/api/v1/lua/gte (the gdb stub doesn't expose COP2 at all).
|
||||||
# (the gdb stub doesn't expose COP2 at all).
|
|
||||||
#
|
#
|
||||||
# usage:
|
# usage:
|
||||||
# .\scripts\launch_pcsx_debug.ps1
|
# .\scripts\launch_pcsx_debug.ps1
|
||||||
@@ -84,7 +83,8 @@ try {
|
|||||||
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/api/v1/lua/gte" -UseBasicParsing -TimeoutSec 5
|
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/api/v1/lua/gte" -UseBasicParsing -TimeoutSec 5
|
||||||
$firstLine = ([System.Text.Encoding]::UTF8.GetString($r.Content) -split "`n")[0]
|
$firstLine = ([System.Text.Encoding]::UTF8.GetString($r.Content) -split "`n")[0]
|
||||||
Write-Host "GTE handler OK: $firstLine" -ForegroundColor Green
|
Write-Host "GTE handler OK: $firstLine" -ForegroundColor Green
|
||||||
} catch {
|
}
|
||||||
|
catch {
|
||||||
Write-Warning "GTE handler NOT responding: $_"
|
Write-Warning "GTE handler NOT responding: $_"
|
||||||
Write-Host "Check the pcsx-redux Lua Console for debug cli messages." -ForegroundColor Yellow
|
Write-Host "Check the pcsx-redux Lua Console for debug cli messages." -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-40
@@ -27,50 +27,34 @@
|
|||||||
local _bootstrap_dir = debug.getinfo(1, "S").source:match("^@?(.*[/\\])") or "./"
|
local _bootstrap_dir = debug.getinfo(1, "S").source:match("^@?(.*[/\\])") or "./"
|
||||||
local duffle = dofile(_bootstrap_dir .. "../duffle_paths.lua")
|
local duffle = dofile(_bootstrap_dir .. "../duffle_paths.lua")
|
||||||
|
|
||||||
--- ════════════════════════════════════════════════════════════════════════════
|
-- ════════════════════════════════════════════════════════════════════════════
|
||||||
--- THE GPR ALLOCATION POOL — what is allocatable, and (more importantly) WHY
|
-- THE GPR ALLOCATION POOL — what's allocatable, and (more importantly) WHY
|
||||||
--- ════════════════════════════════════════════════════════════════════════════
|
-- ════════════════════════════════════════════════════════════════════════════
|
||||||
---
|
--
|
||||||
--- The auto-reg pass picks physical GPRs for `atom_auto_reg(...)` / `phase_auto_reg(...)` markers.
|
-- The auto-reg pass picks physical GPRs for `atom_auto_reg(...)` / `phase_auto_reg(...)` markers.
|
||||||
--- It allocates from a FIXED 10-register pool.
|
-- The 24-register pool covers R2-R25 (the user/atom allocatable surface):
|
||||||
--- This comment block makes the inclusion AND exclusion criteria obvious so a reader doesn't have
|
-- R_T0..R_T7, R_V0..R_V1, R_A0..A3, R_S0..S7, R_T8..T9.
|
||||||
--- to grep lottes_tape.h + mips.h to understand the design.
|
-- Excluded (and never added to the pool):
|
||||||
---
|
-- R_0 (code 0) — hardwired zero. Cannot be written.
|
||||||
--- ── WHAT'S IN THE POOL (10 GPRs, all caller-trash per the O32 ABI) ────────
|
-- R_AT (code 1) — assembler temporary. Reserved by the MIPS O32 ABI.
|
||||||
--- R_T0..R_T7 (GPR codes 8..15), R_V0..R_V1 (GPR codes 2..3)
|
-- R_A0..A3 — explicitly omitted above even though their integer codes
|
||||||
--- The workhorse of every atom body. The uesr should be aware of atom allocation across atoms they chain.
|
-- map to POOL entries; the pool-construction loop below
|
||||||
--- If they have a collision it means either they didn't saturate the register file optimally for a phase,
|
-- only references the POOL string literals, never the
|
||||||
--- or the may have made the workload to large for the run.
|
-- integer codes, so they are NOT auto-allocated by default.
|
||||||
---
|
-- (A0-A3 become available when the user adds them to
|
||||||
--- ── WHAT'S NOT IN THE POOL — and WHY (the "obvious exclusions") ────────────
|
-- POOL or hardcodes an R_A0 reference in the atom body.)
|
||||||
--- R_T9 (GPR code 25) — R_TapePtr, the tape instruction stream pointer.
|
-- R_K0/K1 (codes 26-27) — kernel / interrupt handler reserves. Never touched by user code.
|
||||||
--- Owned by the tape runtime (in tape_run / tape_run_a02_s07).
|
-- R_GP/SP/FP/RA (codes 28-31) — R_SP/R_FP/R_RA are tape-runtime carriers between
|
||||||
--- `rgcc(R_TapePtr)` register-variable ties the C compiler's view to $t9 across the whole tape_run.
|
-- tape_enter and tape_exit; R_GP stays the host global pointer.
|
||||||
--- The auto-reg pass MUST NOT clobber this; doing so would desync the C-side tape pointer from the
|
|
||||||
--- hardware pointer and crash on the next tape_run.
|
|
||||||
---
|
|
||||||
--- R_T8 (GPR code 24) — R_AtomJmp, the atom-jump register used by the 4-word yield handshake.
|
|
||||||
--- Every `mac_yield()` / `mac_yield_tail` does `load_word R_AtomJmp, R_TapePtr, 0` then
|
|
||||||
--- `jump_reg R_AtomJmp`. The auto-reg pass MUST NOT clobber this either, or the atom dispatcher breaks.
|
|
||||||
--- Owned by the tape runtime, same family as R_TapePtr.
|
|
||||||
---
|
|
||||||
--- R_AT (GPR code 1) — Assembler temporary. Reserved by the MIPS O32 ABI for pseudoinstruction expansion
|
|
||||||
--- (lottes_tape.h:86, mips.h:93). The ISA's psuedo instructions use it as a scratch temporary.
|
|
||||||
---
|
|
||||||
--- R_A0..A3 (codes 4..7) — Function arguments. Used in tape_run_a02_s07, see below.
|
|
||||||
--- R_S0..S7 (codes 16..23) — Callee-saved. Preserved across C-ABI calls by convention.
|
|
||||||
--- The `tape_run_a02_s07` variant clobbers them deliberately, but the default `tape_run` does NOT.
|
|
||||||
--- Kept out of POOL to preserve the conservative default.
|
|
||||||
--- Add them in a separate "big clobber" pool if/when needed.
|
|
||||||
---
|
|
||||||
--- R_K0/K1 (codes 26..27) — Kernel / interrupt handler reserves. Never touched by user code; OS-internal.
|
|
||||||
--- R_GP/SP/FP/RA (codes 28..31) — Stack frame + return-address. Owned by the C compiler; never allocatable.
|
|
||||||
--- R_0 (code 0) — Hardwired zero. Cannot be written.
|
|
||||||
---
|
---
|
||||||
local POOL = {
|
local POOL = {
|
||||||
"R_T0", "R_T1", "R_T2", "R_T3",
|
"R_T0", "R_T1", "R_T2", "R_T3",
|
||||||
"R_T4", "R_T5", "R_T6", "R_T7",
|
"R_T4", "R_T5", "R_T6", "R_T7",
|
||||||
"R_V0", "R_V1",
|
"R_V0", "R_V1",
|
||||||
|
"R_A0", "R_A1", "R_A2", "R_A3",
|
||||||
|
"R_S0", "R_S1", "R_S2", "R_S3",
|
||||||
|
"R_S4", "R_S5", "R_S6", "R_S7",
|
||||||
|
"R_T8", "R_T9",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Map from integer MIPS GPR code (the `code` field on AliasEntry) to the physical GPR ident in POOL.
|
-- Map from integer MIPS GPR code (the `code` field on AliasEntry) to the physical GPR ident in POOL.
|
||||||
@@ -80,8 +64,12 @@ local POOL = {
|
|||||||
-- are deliberately omitted — see the comment block above for the WHY of each exclusion.
|
-- are deliberately omitted — see the comment block above for the WHY of each exclusion.
|
||||||
local INT_CODE_TO_POOL_GPR = {
|
local INT_CODE_TO_POOL_GPR = {
|
||||||
[2] = "R_V0", [3] = "R_V1",
|
[2] = "R_V0", [3] = "R_V1",
|
||||||
|
[4] = "R_A0", [5] = "R_A1", [6] = "R_A2", [7] = "R_A3",
|
||||||
[8] = "R_T0", [9] = "R_T1", [10] = "R_T2", [11] = "R_T3",
|
[8] = "R_T0", [9] = "R_T1", [10] = "R_T2", [11] = "R_T3",
|
||||||
[12] = "R_T4", [13] = "R_T5", [14] = "R_T6", [15] = "R_T7",
|
[12] = "R_T4", [13] = "R_T5", [14] = "R_T6", [15] = "R_T7",
|
||||||
|
[16] = "R_S0", [17] = "R_S1", [18] = "R_S2", [19] = "R_S3",
|
||||||
|
[20] = "R_S4", [21] = "R_S5", [22] = "R_S6", [23] = "R_S7",
|
||||||
|
[24] = "R_T8", [25] = "R_T9",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Stable sort for deterministic allocation order.
|
-- Stable sort for deterministic allocation order.
|
||||||
@@ -109,7 +97,7 @@ local function allocate_phase(phase_label, decls)
|
|||||||
line = 0,
|
line = 0,
|
||||||
msg = string.format("phase_register_pool_exhausted: "
|
msg = string.format("phase_register_pool_exhausted: "
|
||||||
.. "phase '%s' requested symbol '%s' but the pool has no remaining registers "
|
.. "phase '%s' requested symbol '%s' but the pool has no remaining registers "
|
||||||
.. "(max 10 per phase: R_T0..R_T7 + R_V0..R_V1). Split the phase or use hardcoded GPRs."
|
.. "(max 24 per phase: R_T0..R_T7 + R_V0..R_V1 + R_A0..R_A3 + R_S0..R_S7 + R_T8..R_T9). Split the phase or use hardcoded GPRs."
|
||||||
, phase_label, sym),
|
, phase_label, sym),
|
||||||
}
|
}
|
||||||
return result, errors
|
return result, errors
|
||||||
|
|||||||
@@ -2506,13 +2506,11 @@ local function check_binds_no_substruct_deref(_src, pipe_ctx, findings)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- ════════════════════════════════════════════════════════════════════════════
|
|
||||||
-- ════════════════════════════════════════════════════════════════════════════
|
-- ════════════════════════════════════════════════════════════════════════════
|
||||||
-- GTE control-register alias + RT-diagonal + TR-naming helpers and checks
|
-- GTE control-register alias + RT-diagonal + TR-naming helpers and checks
|
||||||
-- ════════════════════════════════════════════════════════════════════════════
|
-- ════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
--- Resolve a `gte_cr_<Alias>` ident to its alias-group entry, or nil if the alias
|
--- Resolve a `gte_cr_<Alias>` ident to its alias-group entry, or nil if the alias is in a distinct-slot group (or the alias name is not a known C2 control-register alias).
|
||||||
--- is in a distinct-slot group (or the alias name is not a known C2 control-register alias).
|
|
||||||
--- Reads `M.GTE_CR_ALIAS_GROUPS` from `duffle.lua`.
|
--- Reads `M.GTE_CR_ALIAS_GROUPS` from `duffle.lua`.
|
||||||
local function find_alias_pair_for(alias_name, duffle)
|
local function find_alias_pair_for(alias_name, duffle)
|
||||||
local groups = (duffle and duffle.GTE_CR_ALIAS_GROUPS) or {}
|
local groups = (duffle and duffle.GTE_CR_ALIAS_GROUPS) or {}
|
||||||
@@ -2531,11 +2529,9 @@ local function is_ctrl_r_transfer(c)
|
|||||||
return c.ident == "gte_mv_to_ctrl_r" or c.ident == "gte_mv_from_ctrl_r"
|
return c.ident == "gte_mv_to_ctrl_r" or c.ident == "gte_mv_from_ctrl_r"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Resolve a token's source line. The per-token `line` is the body-relative
|
-- Resolve a token's source line.
|
||||||
-- line; `atom.line` is the source line of the atom declaration; `line_in_body`
|
-- The per-token `line` is the body-relative line; `atom.line` is the source line of the atom declaration; `line_in_body` (atom.paths) maps a body-relative line to its source line.
|
||||||
-- (atom.paths) maps a body-relative line to its source line. The arithmetic
|
-- The arithmetic `atom.line + line_in_body[tok.rel] - 1` matches the convention used by check_abi_handoff and check_control_transfer_delay_slot_use elsewhere.
|
||||||
-- `atom.line + line_in_body[tok.rel] - 1` matches the convention used by
|
|
||||||
-- check_abi_handoff and check_control_transfer_delay_slot_use elsewhere.
|
|
||||||
local function atom_body_token_source_line(atom, token, line_in_body)
|
local function atom_body_token_source_line(atom, token, line_in_body)
|
||||||
if line_in_body == nil or token == nil or token.rel == nil then
|
if line_in_body == nil or token == nil or token.rel == nil then
|
||||||
return atom.line or 0
|
return atom.line or 0
|
||||||
@@ -2584,14 +2580,11 @@ local function ctrl_writes_in_atom(atom)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check #N: gte_cr_alias_writes
|
-- Check #N: gte_cr_alias_writes
|
||||||
-- Fires one warning per atom per alias-group when the atom body touches two
|
-- Fires one warning per atom per alias-group when the atom body touches two distinct aliases from the same group.
|
||||||
-- distinct aliases from the same group. Aliases within a group write to the
|
-- Aliases within a group write to the same C2 control-register slot on real silicon; cross-alias writes inside one atom body silently clobber each other.
|
||||||
-- same C2 control-register slot on real silicon; cross-alias writes inside
|
|
||||||
-- one atom body silently clobber each other.
|
|
||||||
--
|
--
|
||||||
-- Severity: warning. Build continues. The libgte outer-product convention
|
-- Severity: warning. Build continues.
|
||||||
-- uses only RT-row aliases (which are NOT in `M.GTE_CR_ALIAS_GROUPS`), so
|
-- The libgte outer-product convention uses only RT-row aliases (which are NOT in `M.GTE_CR_ALIAS_GROUPS`), so the canonical convention does not trigger this check.
|
||||||
-- the canonical convention does not trigger this check.
|
|
||||||
local function check_gte_cr_alias_writes(atom, pipe_ctx, findings)
|
local function check_gte_cr_alias_writes(atom, pipe_ctx, findings)
|
||||||
local groups = pipe_ctx.gte_cr_alias_groups or {}
|
local groups = pipe_ctx.gte_cr_alias_groups or {}
|
||||||
if not next(groups) then return end
|
if not next(groups) then return end
|
||||||
@@ -2650,14 +2643,11 @@ end
|
|||||||
|
|
||||||
-- Check #N+1: rtdiagonal_completeness
|
-- Check #N+1: rtdiagonal_completeness
|
||||||
-- Fires one info per atom body when the bare `gte_cmdw_mvmva` macro is used.
|
-- Fires one info per atom body when the bare `gte_cmdw_mvmva` macro is used.
|
||||||
-- The bare macro encodes only the cmd field; the canonical libgte-2-pass
|
-- The bare macro encodes only the cmd field; the canonical libgte-2-pass shape uses `gte_cmdw_mvmva_c11_pass2_exact = 0x4A49E012` (gte.h:430).
|
||||||
-- shape uses `gte_cmdw_mvmva_c11_pass2_exact = 0x4A49E012` (gte.h:430).
|
|
||||||
--
|
--
|
||||||
-- Severity: info by default. Escalates to warning when
|
-- Severity: info by default. Escalates to warning when `GTE_RT_DIAGONAL_STRICT=1` env var is set (CI / production builds).
|
||||||
-- `GTE_RT_DIAGONAL_STRICT=1` env var is set (CI / production builds).
|
|
||||||
--
|
--
|
||||||
-- The bare macro IS the right call for the canonical libgte outer-product
|
-- The bare macro IS the right call for the canonical libgte outer-product convention, so this is an opt-out hint rather than a hard warning.
|
||||||
-- convention, so this is an opt-out hint rather than a hard warning.
|
|
||||||
local function check_rtdiagonal_completeness(atom, _pipe_ctx, findings)
|
local function check_rtdiagonal_completeness(atom, _pipe_ctx, findings)
|
||||||
local tokens = atom.paths and atom.paths.tokens or {}
|
local tokens = atom.paths and atom.paths.tokens or {}
|
||||||
local tc = atom.paths and atom.paths.tok_class or {}
|
local tc = atom.paths and atom.paths.tok_class or {}
|
||||||
|
|||||||
+14
-25
@@ -91,11 +91,9 @@ if (-not (Test-Path -LiteralPath $path_pcsx_packages)) {
|
|||||||
New-Item -ItemType Directory -Path $path_pcsx_packages -Force | Out-Null
|
New-Item -ItemType Directory -Path $path_pcsx_packages -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Download anything missing. Skip the package entirely if its dir already has
|
# Download anything missing.
|
||||||
# any contents (the legacy packages.config style means the targets file
|
# Skip the package entirely if its dir already has any contents (the legacy packages.config style means the targets file location varies per package
|
||||||
# location varies per package — `luajit.native` puts it at build/native/,
|
# — `luajit.native` puts it at build/native/, `glfw` puts it elsewhere — so we can't probe a specific path; just check whether the dir is non-empty).
|
||||||
# `glfw` puts it elsewhere — so we can't probe a specific path; just check
|
|
||||||
# whether the dir is non-empty).
|
|
||||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
foreach ($pkg in $required_packages.Values) {
|
foreach ($pkg in $required_packages.Values) {
|
||||||
$pkgDir = Join-Path $path_pcsx_packages ('{0}.{1}' -f $pkg.id, $pkg.version)
|
$pkgDir = Join-Path $path_pcsx_packages ('{0}.{1}' -f $pkg.id, $pkg.version)
|
||||||
@@ -122,24 +120,18 @@ foreach ($pkg in $required_packages.Values) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
# isoffi.lua size guard — `core.vcxproj` #includes src/core/isoffi.lua into
|
# isoffi.lua size guard — `core.vcxproj` #includes src/core/isoffi.lua into luaiso.cc via the `-- lualoader, R"EOF(...)EOF"` trick.
|
||||||
# luaiso.cc via the `-- lualoader, R"EOF(...)EOF"` trick. The raw string
|
# The raw string literal between R"EOF(-- and -- )EOF" must stay under ~16,379 bytes or MSVC (19.44) fails with C2026 (its actual raw-string limit is 16,384, minus 5 bytes for the `-- lualoader, ` prefix).
|
||||||
# literal between R"EOF(-- and -- )EOF" must stay under ~16,379 bytes or
|
# If the upstream file grows past that, trim it: remove license header, trailing whitespace, blank separators, inline comments, and shrink 4-space indent to 2-space.
|
||||||
# MSVC (19.44) fails with C2026 (its actual raw-string limit is 16,384,
|
|
||||||
# minus 5 bytes for the `-- lualoader, ` prefix). If the upstream file
|
|
||||||
# grows past that, trim it: remove license header, trailing whitespace,
|
|
||||||
# blank separators, inline comments, and shrink 4-space indent to 2-space.
|
|
||||||
# Idempotent — only writes when the raw string exceeds the limit.
|
# Idempotent — only writes when the raw string exceeds the limit.
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
$path_isoffi = join-path $path_pcsx_redux 'src\core\isoffi.lua'
|
$path_isoffi = join-path $path_pcsx_redux 'src\core\isoffi.lua'
|
||||||
if (Test-Path -LiteralPath $path_isoffi) {
|
if (Test-Path -LiteralPath $path_isoffi) {
|
||||||
$content = Get-Content -LiteralPath $path_isoffi -Raw -Encoding utf8
|
$content = Get-Content -LiteralPath $path_isoffi -Raw -Encoding utf8
|
||||||
$startMarker = $content.IndexOf('R"EOF(--')
|
$startMarker = $content.IndexOf('R"EOF(--')
|
||||||
$endMarker = $content.IndexOf('-- )EOF"')
|
$endMarker = $content.IndexOf('-- )EOF"')
|
||||||
$literalLen = if ($startMarker -ge 0 -and $endMarker -gt $startMarker) {
|
$literalLen = if ($startMarker -ge 0 -and $endMarker -gt $startMarker) { $endMarker - ($startMarker + 8) } else { -1 }
|
||||||
$endMarker - ($startMarker + 8)
|
|
||||||
} else { -1 }
|
|
||||||
# Effective MSVC raw-string limit for the lualoader prefix is 16379 bytes.
|
# Effective MSVC raw-string limit for the lualoader prefix is 16379 bytes.
|
||||||
if ($literalLen -gt 16379) {
|
if ($literalLen -gt 16379) {
|
||||||
Write-Host "isoffi.lua raw string is $literalLen bytes (>16379); trimming for MSVC C2026 limit."
|
Write-Host "isoffi.lua raw string is $literalLen bytes (>16379); trimming for MSVC C2026 limit."
|
||||||
@@ -168,8 +160,7 @@ if (Test-Path -LiteralPath $path_isoffi) {
|
|||||||
$newLines += $line
|
$newLines += $line
|
||||||
}
|
}
|
||||||
($newLines -join "`n") | Out-File -LiteralPath $path_isoffi -Encoding utf8 -NoNewline
|
($newLines -join "`n") | Out-File -LiteralPath $path_isoffi -Encoding utf8 -NoNewline
|
||||||
$newLen = ((Get-Content -LiteralPath $path_isoffi -Raw -Encoding utf8) `
|
$newLen = ((Get-Content -LiteralPath $path_isoffi -Raw -Encoding utf8) -replace '.*R"EOF\(--', '' -replace '-- \)EOF".*', '').Length
|
||||||
-replace '.*R"EOF\(--', '' -replace '-- \)EOF".*', '').Length
|
|
||||||
Write-Host "isoffi.lua trimmed: $literalLen -> $newLen bytes of raw string content."
|
Write-Host "isoffi.lua trimmed: $literalLen -> $newLen bytes of raw string content."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,13 +222,11 @@ $lfs_dll_import = join-path $luajit_lib_dir 'libluajit-5.1.dll.a'
|
|||||||
|
|
||||||
$path_openbios = join-path $path_pcsx_redux 'src\mips\openbios'
|
$path_openbios = join-path $path_pcsx_redux 'src\mips\openbios'
|
||||||
|
|
||||||
# Wipe stale *.dep files across src\mips. These cache absolute paths to the
|
# Wipe stale *.dep files across src\mips.
|
||||||
# GCC headers directory; if the toolchain was upgraded (e.g. v14.2.0 → v16.1.0)
|
# These cache absolute paths to the GCC headers directory; if the toolchain was upgraded (e.g. v14.2.0 → v16.1.0)
|
||||||
# Make reads the stale paths and aborts with "no rule to make target .../stddef.h".
|
# Make reads the stale paths and aborts with "no rule to make target .../stddef.h".
|
||||||
# `make clean` in openbios only clears its own dir — subdirs like
|
# `make clean` in openbios only clears its own dir — subdirs like common/crt0/, modplayer/, and shell/ keep their stale .dep files.
|
||||||
# common/crt0/, modplayer/, and shell/ keep their stale .dep files. Easier to
|
# Easier to just delete the lot before each build than to teach every Makefile about deepclean recursion.
|
||||||
# just delete the lot before each build than to teach every Makefile about
|
|
||||||
# deepclean recursion.
|
|
||||||
Get-ChildItem -Path (join-path $path_pcsx_redux 'src\mips') -Recurse -Filter '*.dep' -ErrorAction SilentlyContinue |
|
Get-ChildItem -Path (join-path $path_pcsx_redux 'src\mips') -Recurse -Filter '*.dep' -ErrorAction SilentlyContinue |
|
||||||
ForEach-Object { Remove-Item -LiteralPath $_.FullName -Force }
|
ForEach-Object { Remove-Item -LiteralPath $_.FullName -Force }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user