diff --git a/code/duffle/gcc_asm.h b/code/duffle/gcc_asm.h index 2f3fe0a..08c6bfe 100644 --- a/code/duffle/gcc_asm.h +++ b/code/duffle/gcc_asm.h @@ -298,20 +298,58 @@ #define asm_clobber(...) : __VA_ARGS__ /* `asm_inline(...)` dispatches into `_INL_` to emit up to 99 encoded - * instruction words. This is the "compiled-instruction" form of `asm_code`. */ + * instruction words. This is the "compiled-instruction" form of `asm_code`. + * + * Result is a 3-colon statement body WITHOUT the final clobber section: + * ".word %c0, %c1, ..." : : "i"(p0), "i"(p1) + * |----- code -----| |--- empty ---| |------- inputs -------| + * + * Append `: clobbers` after it and wrap in `asm volatile (...)`. */ #define asm_inline(...) m_expand(glue(_INL_, _ASM_COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)) -/* `asm_blob(inlines, clobbers)` — the original 2-section shell. Emits - * `asm volatile ( inlines clobbers )` - * which is the `.word`-only shape (no inputs/outputs): the inlines expand - * to `".word %c0, ..." : : "i"(...)` already including the empty output - * and input sections via their trailing `:`, so clobbers just tacks on the - * end. */ -// #define asm_blob(inlines, clobbers) asm volatile ( inlines clobbers ) -// Not a fan rather just do asm volatile ( ... ) +/* ============================================================================ + * SECTION-STRIP HELPER — let users wrap multi-token sections in `(...)` so + * the preprocessor treats them as a single argument. + * ============================================================================ + * + * Without paren-stripping, calling + * asm_block_4(asm_inline(w0, w1), , "r"(p), "$2", "$8") + * would tokenize the last `clb` as TWO args (`"$2"` and `"$8"`) because + * the preprocessor counts top-level commas. The parens `("$2", "$8")` + * shield the comma, so the preprocessor sees ONE arg — but those parens + * would then survive into the C source as a syntax error. + * + * The trick: + * _strip((a, b, c)) -> _strip_IMPL (a, b, c) -> _strip_IMPL a, b, c + * (function-call syntax!) + * -> a, b, c + * + * The outer call is on `a, b, c` (which is fine as macro args), and the + * variadic capture `__VA_ARGS__` then re-emits the comma-separated list. */ +#define _strip(x) _strip_IMPL x +#define _strip_IMPL(...) __VA_ARGS__ -/* `asm_block(code, outs, ins, clb)` — the full 4-section shell. Each - * argument is expected to already include its own leading `:` (via the - * `asm_out` / `asm_in` / `asm_clb` builders) or be empty. The `code` - * argument should NOT have a leading `:`. */ -#define asm_block(code, outs, ins, clb) asm volatile ( code outs ins clb ) +/* ============================================================================ + * asm_block_4(code, outs, ins, clb) — the assembler for the 4-section form + * ============================================================================ + * + * You pass 4 section BODIES (no colons). To allow multi-token sections, wrap + * them in `(...)` — the parens shield internal commas from the preprocessor + * and are stripped by the `_strip` helper. + * + * asm_block_4( + * (asm_inline(w0, w1)), // code body — parens protect inner commas + * (), // empty outputs + * ("r"(p)), // inputs body + * ("$2", "$8", "memory") // clobbers body + * ) + * + * Expands to: + * asm volatile( asm_inline(w0, w1) : : "r"(p) : "$2", "$8", "memory" ) + * |-- 3 colons inserted here --| + * + * If a section is a single token (no internal commas), you can omit the + * parens: `asm_block_4("...", , "r"(p), "$2")`. + */ +#define asm_block_4(code, outs, ins, clb) \ + asm volatile( _strip(code) : _strip(outs) : _strip(ins) : _strip(clb) ) diff --git a/code/duffle/gte.h b/code/duffle/gte.h index 9e3ac4a..3894116 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -207,45 +207,50 @@ enum { _C2_OPS_ = 0 * hardwired form the "placeholder-pun" — GCC is forced to bind r_ptr to * $12, which is exactly the register the .word constants expect. * - * Uses asm_volatile_4(code, outs, ins, clb) from gcc_asm.h. + * Uses asm_block_4(code, outs, ins, clb) from gcc_asm.h. * asm_inline(...) produces the 2-colon code:outputs:inputs body * "r"(r_ptr) is the runtime-input section body * "$2", ..., "$12" is the clobber section body - * asm_volatile_4() joins them with 3 colons and wraps in asm volatile + * asm_block_4() joins them with 3 colons and wraps in asm volatile + * + * The parens `(...)` around each section let the preprocessor treat the + * section's contents as a single arg (shielding internal commas), and + * the `_strip` helper inside asm_block_4 removes those parens so the + * final C code is clean. */ #define gte_load_v0(r_ptr) \ - asm_volatile_4( \ - (asm_inline( gte_lwc2_v0_RT4, gte_lwc2_v0z_RT4 )), \ - (), \ - ("r"(r_ptr)), \ - ("$2", "$8", "$9", "$31", "memory", "$12") \ + asm_block_4( \ + (asm_inline( gte_lwc2_v0_RT4, gte_lwc2_v0z_RT4 )), \ + (), \ + ("r"(r_ptr)), \ + ("$2", "$8", "$9", "$31", "memory", "$12") \ ) #define gte_load_v1(r_ptr) \ - asm_volatile_4( \ - (asm_inline( gte_lwc2_v1_RT4, gte_lwc2_v1z_RT4 )), \ - (), \ - ("r"(r_ptr)), \ - ("$2", "$8", "$9", "$31", "memory", "$12") \ + asm_block_4( \ + (asm_inline( gte_lwc2_v1_RT4, gte_lwc2_v1z_RT4 )), \ + (), \ + ("r"(r_ptr)), \ + ("$2", "$8", "$9", "$31", "memory", "$12") \ ) #define gte_load_v2(r_ptr) \ - asm_volatile_4( \ - (asm_inline( gte_lwc2_v2_RT4, gte_lwc2_v2z_RT4 )), \ - (), \ - ("r"(r_ptr)), \ - ("$2", "$8", "$9", "$31", "memory", "$12") \ + asm_block_4( \ + (asm_inline( gte_lwc2_v2_RT4, gte_lwc2_v2z_RT4 )), \ + (), \ + ("r"(r_ptr)), \ + ("$2", "$8", "$9", "$31", "memory", "$12") \ ) /* All three at once -- the canonical prelude to gte_cmd_rtpt. */ #define gte_load_v0v1v2(r_ptr) \ - asm_volatile_4( \ - (asm_inline( gte_lwc2_v0_RT4, gte_lwc2_v0z_RT4, \ - gte_lwc2_v1_RT4, gte_lwc2_v1z_RT4, \ - gte_lwc2_v2_RT4, gte_lwc2_v2z_RT4 )), \ - (), \ - ("r"(r_ptr)), \ - ("$2", "$8", "$9", "$31", "memory", "$12") \ + asm_block_4( \ + (asm_inline( gte_lwc2_v0_RT4, gte_lwc2_v0z_RT4, \ + gte_lwc2_v1_RT4, gte_lwc2_v1z_RT4, \ + gte_lwc2_v2_RT4, gte_lwc2_v2z_RT4 )), \ + (), \ + ("r"(r_ptr)), \ + ("$2", "$8", "$9", "$31", "memory", "$12") \ ) /**