Extract out a cross roduct component.

This commit is contained in:
ed
2026-08-17 10:34:43 -04:00
parent e79c364b40
commit d4795cf9de
3 changed files with 116 additions and 9 deletions
+16
View File
@@ -211,6 +211,18 @@ WORD_COUNT(mac_gte_mv_to_cr_diag_v3s4, 3)
, gte_mv_to_data_r(v.z, C2_IR3)
WORD_COUNT(mac_gte_ld_ir123_v3s4, 3)
/* atom_dbg_skip */
#define mac_gte_op_cross_v3s4(a, b) \
mac_gte_mv_to_cr_diag_v3s4(a) \
GteDelay_ /* RT diagonal: D1 = a.x, D2 = a.y, D3 = a.z */ \
, mac_gte_ld_ir123_v3s4(b) \
GteDelay_ /* IR: second operand (b.xyz) */ \
, gte_cmdw_cross /* OP: MAC1/2/3 = a × b (S12.20) */ \
, mac_gte_mv_from_mac123_v3s4(a) \
GteDelay_ /* Read MAC1/2/3 → a.xyz (overwrites source-A's load targets) */ \
, mac_shift_aright_v3s4_self(a, 12) /* Right-shift MAC by 12 (S12.20 → S12.0 OuterProduct12) */
WORD_COUNT(mac_gte_op_cross_v3s4, 16)
/* atom_dbg_skip */
#define mac_gte_store_f3(r_primitive_cursor) \
gte_sw(C2_SXY0, r_primitive_cursor, O_(Poly_F3,p0)) \
@@ -322,6 +334,10 @@ WORD_COUNT(mac_gte_general_purpose_interopolation, 10)
, gte_mv_from_data_r(fr_mac3, C2_MAC3)
WORD_COUNT(mac_gte_mv_from_data_r_mac123, 3)
#define mac_gte_mv_from_mac123_v3s4(v) \
mac_gte_mv_from_data_r_mac123(v.x, v.y, v.z)
WORD_COUNT(mac_gte_mv_from_mac123_v3s4, 3)
/* atom_dbg_skip */
#define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \
mac_load_word_imm(reg_transfer, cmd) \
+12 -8
View File
@@ -30,6 +30,14 @@ FI_ Slice_MipsCode ac_gte_ld_ir123_v3s4(AtomBuilder_R ab, Reg_(V3_S4) v) MipsAto
gte_mv_to_data_r(v.z, C2_IR3),
})
FI_ Slice_MipsCode ac_gte_op_cross_v3s4(AtomBuilder_R ab, Reg_(V3_S4) a, Reg_(V3_S4) b) atom_dbg_skip MipsAtomComp_Proc_(ab, {
mac_gte_mv_to_cr_diag_v3s4(a), GteDelay_ /* RT diagonal: D1 = a.x, D2 = a.y, D3 = a.z */
mac_gte_ld_ir123_v3s4(b), GteDelay_ /* IR: second operand (b.xyz) */
gte_cmdw_cross, /* OP: MAC1/2/3 = a × b (S12.20) */
mac_gte_mv_from_mac123_v3s4(a), GteDelay_ /* Read MAC1/2/3 → a.xyz (overwrites source-A's load targets) */
mac_shift_aright_v3s4_self(a, 12), /* Right-shift MAC by 12 (S12.20 → S12.0 OuterProduct12) */
})
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3.
* PIPELINE: post-RTPT (SXY0=v0.screen, SXY1=v1.screen, SXY2=v2.screen). */
FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, {
@@ -173,6 +181,9 @@ MipsAtomComp_Proc_(ab, {
gte_mv_from_data_r(fr_mac3, C2_MAC3),
})
FI_ Slice_MipsCode ac_gte_mv_from_mac123_v3s4(AtomBuilder_R ab, Reg_(V3_S4) v) MipsAtomComp_ProcMap_(ab, mac_gte_mv_from_data_r_mac123(v.x, v.y, v.z))
#pragma endregion MACs (Mips Atom Components)
#pragma region Atom Procs
@@ -348,18 +359,11 @@ atom_info(atom_bind(Binds_gte_cross_v3s4)) MipsAtom_Proc_(aa, {
mac_load_v3s4(r.a, r.src_a, 0), LdSlot_
mac_load_v3s4(r.b, r.src_b, 0), LdSlot_
mac_gte_mv_to_cr_diag_v3s4(r.a), GteDelay_ /* RT diagonal: D1 = a.x, D2 = a.y, D3 = a.z. */
mac_gte_ld_ir123_v3s4(r.b), GteDelay_ /* IR: second operand. */
gte_cmdw_cross, /* MAC1/2/3 = a × b */
mac_gte_mv_from_data_r_mac123(r.a.x, r.a.y, r.a.z), GteDelay_ //nop,
mac_shift_aright_v3s4_self(r.a, 12),
mac_gte_op_cross_v3s4(r.a, r.b), /* RT diagonal + IR + OP + MAC read + shift (one component call). */
mac_store_v3s4(r.a, r.out, 0),
mac_yield()
})
#pragma endregion Atom Procs
#pragma region Baked Atoms
+88 -1
View File
@@ -504,16 +504,103 @@ local function strip_trailing_continuation(lines)
end
end
--- Classify a token as a "pure delay marker token" (a delay-marker identifier
--- with no following instruction — only whitespace and/or block comments).
--- Examples that match:
--- * `GteDelay_` → marker alone
--- * `GteDelay_ /* RT diagonal: D1 = a.x... */` → marker + block comment
--- * `GteDelay_ /* RT diagonal: ... */\n\t` → marker + comment + trailing whitespace
--- Examples that DO NOT match (these contain a real instruction after the marker
--- and must be preserved verbatim so the instruction still gets emitted):
--- * `GteDelay_ nop2`
--- * `GteDelay_ add_si(r.dst_ptr, r.scratch, dst_offset)`
---
--- Why this classification matters: the metaprogram emits tokens separated by `,`
--- and joins them with `\<newline>` line continuations. After C preprocessor
--- phase 2 (line splicing), the macro body collapses to a single logical line.
--- Each delay-marker identifier expands to empty (its definition
--- `#define GteDelay_ // ...` consumes the `//` line comment during preprocessing
--- of the definition itself, leaving an empty replacement list). When a token
--- is purely a delay marker with only a trailing comment, the `,` the metaprogram
--- normally adds before each token-after-the-first brackets empty content and
--- produces the syntax error `,,` (`expected expression before ',' token`) at
--- C compile. The metaprogram therefore emits such tokens WITHOUT the leading
--- `,` (see `token_skips_leading_comma`) — but the marker + trailing comment
--- are still emitted verbatim so the annotation is preserved in `gen/macs.h`.
--- @param tok string -- a single token from split_top_level_commas (already trimmed at the start, may contain trailing whitespace + block comment)
--- @return boolean
local function is_pure_delay_marker_token(tok)
local markers = duffle.DELAY_MARKERS
if type(markers) ~= "table" then return false end
-- Identify a leading delay-marker identifier (e.g. `GteDelay_`).
local ident_end = 1
while ident_end <= #tok do
local ch = tok:sub(ident_end, ident_end)
if ch:match("[%w_]") then
ident_end = ident_end + 1
else
break
end
end
local ident = tok:sub(1, ident_end - 1)
if not markers[ident] then return false end
-- Walk the remainder: only whitespace and block comments are allowed.
local scan = ident_end
while scan <= #tok do
local ch = tok:sub(scan, scan)
if ch:match("%s") then
scan = scan + 1
elseif ch == "/" and tok:sub(scan + 1, scan + 1) == "*" then
local close = tok:find("*/", scan + 2, true)
if not close then return false end
scan = close + 2
else
-- Non-whitespace, non-block-comment content: a real instruction
-- follows the marker (e.g. `GteDelay_ nop2`); keep this token intact.
return false
end
end
return true
end
--- Classify a token's "leading comma requirement".
--- Pure delay-marker tokens (`GteDelay_` / `LdSlot_` / `BdSlot_` / `DmaSlot_`
--- followed by whitespace + optional block comment and NOTHING ELSE) expand
--- to empty at C preprocessor time. Emitting them WITHOUT the leading `,`
--- separator that the metaprogram normally adds before each token after the
--- first keeps exactly one `,` between the surrounding real expressions in
--- the spliced macro body:
---
--- * before this rule: `<tok1> ,\t<gdelay> ,\t<tok3>` → after expansion
--- `<tok1> , /* comment */ , <tok3>` → `,,` syntax error.
--- * after this rule: `<tok1> \t<gdelay> ,\t<tok3>` → after expansion
--- `<tok1> /* comment */ , <tok3>` → `<tok1>, <tok3>` — valid.
---
--- Tokens like `GteDelay_ nop2` keep the leading `,` (the marker is followed
--- by a real instruction, so the marker + instruction together need the
--- separator on the LEFT to land between two real expressions).
--- @param tok string
--- @return boolean -- true if the token needs NO leading `,` separator.
local function token_skips_leading_comma(tok)
return is_pure_delay_marker_token(tok)
end
--- Emit the `#define mac_X(sig) \<newline>\t<tok1> \<newline>,\t<tok2> ...` block.
--- Converts `//` line comments to `/* */` block comments in each token so they don't break the C macro `\` line continuations.
---
--- Pure delay-marker tokens (`GteDelay_` / `LdSlot_` / `BdSlot_` / `DmaSlot_` with only a trailing block comment, no real instruction) are emitted WITHOUT a leading `,` separator; the annotation IS preserved in the generated header (so the comment + marker remain visible to anyone reading `gen/macs.h`), but the C preprocessor expands the marker to empty, so leaving the `,` separator out is what stops the `,,` syntax error. See `token_skips_leading_comma` for the contract.
local function emit_macro_body(lines, c, sig, tokens)
for tok_idx = 1, #tokens do
tokens[tok_idx] = convert_line_comments_to_block(tokens[tok_idx])
end
if #tokens == 0 then return end
lines[#lines + 1] = "#define mac_" .. c.name .. "(" .. sig .. ") \\"
lines[#lines + 1] = "\t" .. tokens[1] .. " \\"
for tok_idx = 2, #tokens do
lines[#lines + 1] = ",\t" .. tokens[tok_idx] .. " \\"
local sep = token_skips_leading_comma(tokens[tok_idx]) and "\t" or ",\t"
lines[#lines + 1] = sep .. tokens[tok_idx] .. " \\"
end
strip_trailing_continuation(lines)
end