improving dsl.

This commit is contained in:
2026-07-08 00:30:02 -04:00
parent 0b147a8b0c
commit d0b1bae896
7 changed files with 230 additions and 88 deletions
+1 -1
View File
@@ -420,7 +420,7 @@
* tape_words(mac_yield, 1)
* #define mac_yield() \
* load_word(R_AtomJmp, R_TapePtr, 0), \
* add_ui_1(R_TapePtr, 4), \
* add_ui_self(R_TapePtr, 4), \
* jump_reg(R_AtomJmp), \
* nop
*
+6 -6
View File
@@ -40,7 +40,7 @@
* // Pure command sequence — all bits compile-time:
* asm volatile(
* asm_inline( gte_cmd_rtpt , gte_cmd_nclip , gte_cmd_avsz3 )
* asm_clobber( clb_system )
* asm_clobber( clbr_volatile_gprs )
* );
*
* // Runtime-base-register load — caller picks the base GPR:
@@ -530,7 +530,7 @@ enum {
* zero (standard rotation, no scaling, V0 vector, translation
* vector, no clamp).
*
* Clobbers the caller-saved GPRs via `clb_system` (per the kernel
* Clobbers the caller-saved GPRs via `clbr_volatile_gprs` (per the kernel
* ABI) plus the standard "memory" barrier. Does not clobber any COP2
* data/control register — those have to be saved by the caller if
* they need to survive across the call (RTPT writes SXY0..2, SZ0..3,
@@ -539,7 +539,7 @@ enum {
#define gte_rtpt() \
asm volatile( \
asm_words( nop, nop, gte_cmdw_rtpt ) \
asm_clobber: clb_system \
asm_clobber: clbr_volatile_gprs \
)
#define gte_rtpt_ori() \
@@ -571,7 +571,7 @@ enum {
* (unlike RTPS/RTPT which carry the `gte_cmdw_psyq_compat`
* quirk), so `gte_cmdw_nclip` does NOT OR in any reserved bits.
*
* Clobbers the caller-saved GPRs via `clb_system` (per the kernel
* Clobbers the caller-saved GPRs via `clbr_volatile_gprs` (per the kernel
* ABI) plus the standard "memory" barrier. Does not clobber any COP2
* data/control register - those have to be saved by the caller if
* they need to survive across the call (NCLIP writes MAC0 only; it
@@ -580,7 +580,7 @@ enum {
#define gte_nclip() \
asm volatile( \
asm_words( nop, nop, gte_cmdw_nclip ) \
asm_clobber: clb_system \
asm_clobber: clbr_volatile_gprs \
)
#define gte_stotz(r0) __asm__ volatile("swc2 $7, 0( %0 )" : : "r"(r0) : "memory")
@@ -660,7 +660,7 @@ enum {
, gte_mt( R_T4, 4) \
) \
, r_use(r0) \
asm_clobber: clb_system, rlit(R_T4), rlit(R_T5), rlit(R_T6) \
asm_clobber: clbr_volatile_gprs, rlit(R_T4), rlit(R_T5), rlit(R_T6) \
)
#pragma endregion ASM DSL
+30 -38
View File
@@ -47,11 +47,11 @@ FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; a
add_ui( R_SP, R_SP, -MipsStackAlignment) /* Allocate stack space */
, store_word(R_RA, R_SP, 0) /* Safely backup $ra to the stack */
, load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
, add_ui_1( R_TapePtr, S_(MipsCode)) /* Advance tape */
, jump_nreg( R_AtomJmp) /* jalr $t9 */
, add_ui_self( R_TapePtr, S_(MipsCode)) /* Advance tape */
, call_reg( R_AtomJmp) /* jalr $t9 */
, nop /* Branch delay slot */
, load_word(R_RA, R_SP, 0) /* Restore $ra from stack */
, add_ui_1( R_SP, MipsStackAlignment) /* Deallocate stack space */
, add_ui_self( R_SP, MipsStackAlignment) /* Deallocate stack space */
)
asm_rpins, r_use(tp)
asm_clobber:
@@ -90,7 +90,7 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
* Cost: ~ 4 cycles */
#define mac_yield() \
load_word(R_AtomJmp, R_TapePtr, 0) \
, add_ui_1( R_TapePtr, S_(MipsCode)) \
, add_ui_self( R_TapePtr, S_(MipsCode)) \
, jump_reg( R_AtomJmp) \
, nop
@@ -100,31 +100,24 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
, load_half_u(rId_1, R_FaceCursor, 1 * S_(S2)) \
, load_half_u(rId_2, R_FaceCursor, 2 * S_(S2))
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE
R_AT = rId_[#] << 3;
R_AT += R_VertBase;
R_V0 = R_AT[0];
gte_mt(R_V0, V.xy[#]);
gte_mt(R_V1, V.z [#]);
*/
/* Words: 18; Translates indices to vertex addresses and pushes them to GTE */
#define mac_load_tri_verts(rId_0, rId_1, rId_2) \
shift_ll(R_AT, rId_0, v3s2_byteoff), add_u_1(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0) \
, shift_ll(R_AT, rId_1, v3s2_byteoff), add_u_1(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1) \
, shift_ll(R_AT, rId_2, v3s2_byteoff), add_u_1(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2)
shift_lleft(R_AT, rId_0, v3s2_byteoff), add_u_self(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0) \
, shift_lleft(R_AT, rId_1, v3s2_byteoff), add_u_self(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1) \
, shift_lleft(R_AT, rId_2, v3s2_byteoff), add_u_self(R_AT, R_VertBase), load_word(R_V0, R_AT, O_(V3_S2,x)), load_word(R_V1, R_AT, O_(V3_S2,z)), gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2)
//TODO(Ed): Add more type annotation
/* Words: 11; Correctly inserts a primitive into the Ordering Table linked list */
#define mac_insert_ot_tag(r_otz, prim_length) \
shift_ll( R_T1, r_otz, 2) /* T1 = r_otz * S_(U4) */ \
, add_u( R_T1, R_T1, R_OtBase) /* T1 = & OrderingTable[OTZ] */ \
, load_word(R_AT, R_T1, O_(PolyTag,bf_addr_len)) /* AT = old_ot_head */ \
shift_lleft( R_T1, r_otz, 2) /* T1 = r_otz * S_(U4) */ \
, add_u( R_T1, R_T1, R_OtBase) /* T1 = & OrderingTable[OTZ] */ \
, load_word( R_AT, R_T1, O_(PolyTag,bf_addr_len)) /* AT = old_ot_head */ \
, load_upper_i(R_V0, prim_length) /* V0 = prim_length << 16 (high 16 bits of a tag) */ \
, shift_ll_lr(R_AT, R_AT, S_(PolyTag_len_bits)) /* Strip upper 8 bits (length from prev cell) → keep only low 24 */ \
, or_u( R_AT, R_AT, R_V0) /* Merge length */ \
, store_word(R_AT, R_PrimCursor, O_(PolyTag,bf_addr_len)) /* prim->tag = packed(prim_length, old_addr) */ \
, shift_ll( R_AT, R_PrimCursor, S_(PolyTag_len_bits)) /* AT = (prim_length << 24) | old_addr */ \
, shift_lr( R_AT, R_AT, S_(PolyTag_len_bits)) \
, store_word(R_AT, R_T1, O_(PolyTag,bf_addr_len)) /* OrderingTable[OTZ] = PrimCursor */
, mask_upper( R_AT, R_AT, S_(PolyTag_len_bits)) /* Strip upper 8 bits (length from prev cell) → keep only low 24 */ \
, or_u( R_AT, R_AT, R_V0) /* Merge length */ \
, store_word( R_AT, R_PrimCursor, O_(PolyTag,bf_addr_len)) /* prim->tag = packed(prim_length, old_addr) */ \
, shift_lleft( R_AT, R_PrimCursor, S_(PolyTag_len_bits)) /* AT = (prim_length << 24) | old_addr */ \
, shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)) \
, store_word( R_AT, R_T1, O_(PolyTag,bf_addr_len)) /* OrderingTable[OTZ] = PrimCursor */
#pragma endregion Macro Atom Components
@@ -176,16 +169,15 @@ enum {
* 5. lw $ra, 4($sp); jr $ra ; restore & return
* 6. sp += 8
*/
// TODO(Ed): Annotate magic offsets
internal MipsAtom_(mips_flush_icache) {
add_ui(rstack_ptr, rstack_ptr, -MipsStackAlignment) /* sp -= 8 */
, store_word(rret_addr, rstack_ptr, 4) /* sw $ra, 4($sp) */
, add_ui(rret_0, rdiscard, bios_flushcache) /* addiu $a0, $0, 0x44 */
, add_ui(rtmp_0, rdiscard, bios_table_addr) /* addiu $t0, $0, 0xA0 */
, jump_link(rtmp_0, rret_addr) /* jalr $t0, $ra */
, nop /* BD slot */
, load_word(rret_addr, rstack_ptr, 4) /* lw $ra, 4($sp) */
, jump_reg(rret_addr) /* jr $ra */
, store_word(rret_addr, rstack_ptr, S_(U4)) /* sw $ra, 4($sp) */
, add_ui(rret_0, rdiscard, bios_flushcache) /* addiu $a0, $0, 0x44 */
, add_ui(rtmp_0, rdiscard, bios_table_addr) /* addiu $t0, $0, 0xA0 */
, jump_link(rtmp_0, rret_addr) /* jalr $t0, $ra */
, nop /* BD slot */
, load_word(rret_addr, rstack_ptr, S_(U4)) /* lw $ra, 4($sp) */
, jump_reg(rret_addr) /* jr $ra */
, add_ui(rstack_ptr, rstack_ptr, MipsStackAlignment) /* sp += 8 (BD) */
, mac_yield()
};
@@ -197,7 +189,7 @@ typedef Struct_(Binds_SetGteWorld) {
internal MipsAtom_(set_gte_world) {
/* Pop matrix address from tape into R_T3 ($11) */
load_word(R_T3, R_TapePtr, O_(Binds_SetGteWorld,transform)),
add_ui_1( R_TapePtr, S_(Binds_SetGteWorld)),
add_ui_self( R_TapePtr, S_(Binds_SetGteWorld)),
// TODO(Ed): Annotate magic offsets.
/* Load 3x3 Rotation + 3x1 Translation from R_T3 into GTE CONTROL Regs (ctc2) */
@@ -230,14 +222,14 @@ internal MipsAtom_(diag_color) {
load_upper_i(R_AT, 0x0010), or_i(R_AT, R_AT, 0x0050), store_word(R_AT, R_T7, 16), /* (16, 80) */
add_ui( R_T1, R_0, 10),
shift_ll(R_T1, R_T1, 2),
shift_lleft(R_T1, R_T1, 2),
add_u( R_T1, R_T1, R_T6),
load_word( R_AT, R_T1, 0),
load_upper_i(R_V0, 0x0400), // <--- Fills load delay slot!
store_word( R_AT, R_T7, 0),
shift_ll( R_AT, R_T7, 8), shift_lr(R_AT, R_AT, 8),
shift_lleft( R_AT, R_T7, 8), shift_lright(R_AT, R_AT, 8),
or_u( R_AT, R_AT, R_V0),
store_word(R_AT, R_T1, 0),
@@ -255,15 +247,15 @@ internal MipsAtom_(diag_gte) {
load_half_u(R_T2, R_T4, 4),
/* Load Vertices into GTE */
shift_ll( R_AT, R_T0, 3), add_u( R_AT, R_AT, R_T5),
shift_lleft( R_AT, R_T0, 3), add_u( R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt( R_V0, C2_VXY0), gte_mt( R_V1, C2_VZ0),
shift_ll( R_AT, R_T1, 3), add_u( R_AT, R_AT, R_T5),
shift_lleft( R_AT, R_T1, 3), add_u( R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt( R_V0, C2_VXY1), gte_mt( R_V1, C2_VZ1),
shift_ll( R_AT, R_T2, 3), add_u( R_AT, R_AT, R_T5),
shift_lleft( R_AT, R_T2, 3), add_u( R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt( R_V0, C2_VXY2), gte_mt( R_V1, C2_VZ2),
+118 -28
View File
@@ -1,3 +1,90 @@
/* ============================================================================
* duffle DSL Suffix Conventions (Style B)
* ============================================================================
*
* Every mnemonic in this header follows the same suffix grammar:
*
* _i Immediate value (16-bit constant operand). Combine with
* _u or _s (single-letter modifier + type combined): add_ui,
* add_si. Examples: add_ui, add_si, and_i, or_i, xor_i,
* load_upper_i. and_i is sign-agnostic (andi zero-extends).
* load_upper_i is a unique verb; _i is the immediate marker,
* not a modifier+type combination.
*
* _u Unsigned (no-overflow, no-sign-extension). R-type
* arithmetic examples: add_u, sub_u, mult_u, div_u. I-type
* (combined with _i): add_ui.
*
* _s Signed (overflow-traps, sign-extends). R-type: add_s,
* sub_s, mult_s, div_s, set_lt_s. I-type (combined with _i):
* add_si.
*
* --- Shift family (R-type): verb-modifier-direction ---
* The shift macros use `shift_<modifier><direction>`. Modifier is
* the single letter `l` (logical) or `a` (arithmetic). Direction
* is the word `left` or `right`. Combined: `_lleft`, `_lright`,
* `_aright`. Examples: shift_lleft(rd, rt, shamt) (= sll)
* shift_lright(rd, rt, shamt) (= srl)
* shift_aright(rd, rt, shamt) (= sra)
* (no `_aleft`; MIPS has no `sla` — arithmetic-left is bit-identical
* to logical-left, so use shift_lleft for that case)
*
* --- Jump/Call family ---
* Simple jumps keep the original short names: jump (j), jump_reg
* (jr), jump_link (jalr rs, rd). The jump-and-link-to variants
* (jal, jalr rs with default $ra) get the `call_` verb instead:
* call_addr (jal), call_reg (jalr rs, default $ra).
* Examples: jump(off) (= j)
* jump_reg(rs) (= jr)
* jump_link(rs, rd) (= jalr rs, rd)
* call_reg(rs) (= jalr rs, default $ra)
* call_addr(off) (= jal)
*
* _r Register marker — used only when the register type needs
* disambiguation (e.g., GTE data register vs control
* register). NOT used in plain R-type arithmetic (the
* R-type is implicit). Examples: gte_mv_to_data_r,
* gte_mv_to_ctrl_r.
*
* _self Destination equals one source operand.
* Examples: add_ui_self (I-type, to self),
* add_u_self (R-type, to self).
*
* _mv_to_ Direction: data flows into X.
* Example: gte_mv_to_data_r, gte_mv_to_ctrl_r.
*
* _mv_from_ Direction: data flows out of X.
* Example: gte_mv_from_data_r, gte_mv_from_ctrl_r.
*
* _str String-form — emits inline-asm string instead of `.word`.
* Example: gte_rtpt_asm_str.
*
* _2w / _1w Word count of the emitted sequence.
* Example: load_imm_2w.
*
* _cop2 RESERVED — DO NOT USE in macro names. The `gte_` namespace
* prefix already implies coprocessor 2. Use `c2` only in:
* (a) integer opcode enums (op_lwc2 = 0x32, op_swc2 = 0x3A)
* (b) vendor-mnemonic macro aliases (gte_mtc2, gte_mfc2)
*
* Primitive commands: gp0_cmd_poly_f3 = 0x20 (byte opcode)
* Packed 32-bit cmd: gp0_word_poly_f3(r, g, b) (32-bit, shifted)
*
* Type ordering: domain?_(direction)?_action_target_modifier_type?
* Examples: add_ui (add + unsigned + immediate)
* add_s (add + signed, R-type implicit)
* shift_lleft (shift + logical + left)
* shift_aright (shift + arithmetic + right)
* call_reg(rs) (call + register, $ra implicit)
* gte_mv_to_data_r (gte + mv + to + data + register)
* gte_lw_v0_xy(base) (gte + lw + v0 + xy)
* load_upper_i (load-upper + immediate, unique verb)
*
* Vendor mnemonics (sll, srl, sra, jr, j, jal, jalr) are NOT in this
* header. They live in the opt-in `mips_vendor_sym.h` for users who
* prefer the textbook MIPS assembly mnemonics.
* ============================================================================ */
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "dsl.h"
@@ -243,7 +330,9 @@ enum { _BitOffsets = 0
* load_word(rt, base, off) → lw rt, off(base)
* store_word(rt, base, off) → sw rt, off(base)
* add_ui(rt, rs, imm) → addiu rt, rs, imm
* shift_ll(rd, rt, shamt) → sll rd, rt, shamt
* shift_lleft(rd, rt, shamt) → sll rd, rt, shamt
* shift_lright(rd, rt, shamt) → srl rd, rt, shamt
* shift_aright(rd, rt, shamt) → sra rd, rt, shamt
* jump_reg(rs) → jr rs
* jump_link(rs, rd) → jalr rs (link in rd, default $ra)
* nop → sll $0, $0, 0
@@ -255,7 +344,8 @@ enum { _BitOffsets = 0
#define load_half_u(rt, base, off) enc_i(op_lhu, (base), (rt), (off))
#define store_word(rt, base, off) enc_i(op_sw, (base), (rt), (off))
#define add_ui(rt, rs, imm) enc_i(op_addiu, (rs), (rt), (imm))
#define and_si(rt, rs, imm) enc_i(op_andi, (rs), (rt), (imm))
#define and_i(rt, rs, imm) enc_i(op_andi, (rs), (rt), (imm))
// #define and_si and_i
#define or_i(rt, rs, imm) enc_i(op_ori, (rs), (rt), (imm))
#define xor_i(rt, rs, imm) enc_i(op_xori, (rs), (rt), (imm))
#define load_upper_i(rt, imm) enc_i(op_lui, R_0, (rt), (imm))
@@ -265,7 +355,7 @@ enum { _BitOffsets = 0
#define load_u4 load_word
// Ergonomic add to the same register.
#define add_ui_1(rt_rs, imm) enc_i(op_addiu, (rt_rs), (rt_rs), (imm))
#define add_ui_self(rt_rs, imm) enc_i(op_addiu, (rt_rs), (rt_rs), (imm))
/* Logic Opcodes */
@@ -274,12 +364,12 @@ enum { _BitOffsets = 0
#define xor_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_xor)
#define nor_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_nor)
/* Shift family (R-type). shift_ll/lr/ra: `sll rd, rt, shamt` */
#define shift_ll(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_sll)
#define shift_lr(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_srl)
#define shift_ra(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_sra)
/* Shift family (R-type). shift_lleft/lright/aright: `sll/srl/sra rd, rt, shamt` */
#define shift_lleft(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_sll)
#define shift_lright(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_srl)
#define shift_aright(rd, rt, shamt) enc_r(op_special, R_0, (rt), (rd), (shamt), fc_sra)
#define shift_ll_lr(rd, rt, shamt) shift_ll(rd, rt, shamt), shift_lr(rd, rt, shamt)
#define mask_upper(rd, rt, shamt) shift_lleft(rd, rt, shamt), shift_lright(rd, rt, shamt)
/* jr rs — jump to address in rs. */
#define jump_reg(rs) enc_r(op_special, (rs), R_0, R_0, 0, fc_jr)
@@ -288,14 +378,14 @@ enum { _BitOffsets = 0
* Layout: [op_special][rs:5][rt=0:5][rd:5][shamt=0:5][fc_jalr=0x09] */
#define jump_link(rs, rd) enc_r(op_special, (rs), R_0, (rd), 0, fc_jalr)
/* jalr rs — link in $ra and jump to address in rs (most common form). */
#define jump_nreg(rs) jump_link((rs), R_RA)
/* call_reg rs — jump-and-link to register-held address; link in $ra. */
#define call_reg(rs) jump_link((rs), R_RA)
/* j target — absolute jump within the current 256MB region. */
#define jump(off) enc_i(op_j, R_0, R_0, (off))
/* jal target — absolute call within the current 256MB region. */
#define jump_nlink(off) enc_i(op_jal, R_0, R_0, (off))
/* call_addr off — jump-and-link to immediate address. */
#define call_addr(off) enc_i(op_jal, R_0, R_0, (off))
/* --- Store family (mirrors the load family) --- */
#define store_byte(rt, base, off) enc_i(op_sb, (base), (rt), (off))
@@ -327,17 +417,17 @@ enum { _BitOffsets = 0
#define div_s(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_div)
#define div_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_divu)
#define add_u_1(rd_rs, rt) add_u(rd_rs, rd_rs, rt)
#define add_u_self(rd_rs, rt) add_u(rd_rs, rd_rs, rt)
/* --- Arithmetic I-type (immediate) --- */
#define add_si(rt, rs, imm) enc_i(op_addi, (rs), (rt), (imm))
/* add_ui already exists above as add_ui */
/* --- Set on less than (R-type and I-type) --- */
#define slt_s(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_slt)
#define slt_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_sltu)
#define slt_si(rt, rs, imm) enc_i(op_slti, (rs), (rt), (imm))
#define slt_ui(rt, rs, imm) enc_i(op_sltiu, (rs), (rt), (imm))
#define set_lt_s(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_slt)
#define set_lt_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_sltu)
#define set_lt_si(rt, rs, imm) enc_i(op_slti, (rs), (rt), (imm))
#define set_lt_ui(rt, rs, imm) enc_i(op_sltiu, (rs), (rt), (imm))
/* --- Move from/to HI/LO (mult/div results) --- */
#define mov_from_high(rd) enc_r(op_special, R_0, R_0, (rd), 0, fc_mfhi)
@@ -366,10 +456,10 @@ enum { _BitOffsets = 0
#define breakpoint() enc_r(op_special, R_0, R_0, R_0, 0, fc_break)
/* --- Shift-amount alias (matches the gas convention `\p3 = shamt`) --- */
#define shift_amount(rd, rt, n) shift_ll(rd, rt, n)
#define shift_amount(rd, rt, n) shift_lleft(rd, rt, n)
/* nop — canonical sll $0, $0, 0 */
#define nop shift_ll(rdiscard, rdiscard, 0)
#define nop shift_lleft(rdiscard, rdiscard, 0)
#define load_imm_1w(rt, imm) add_ui((rt), R_0, (imm))
#define load_imm_1w_s0(rt, imm) add_si((rt)), R_0, (imm))
@@ -390,7 +480,7 @@ enum { _BitOffsets = 0
*
* For situations where you need to bypass even this choice (e.g. to
* force a specific encoding for a known discontiguous high/low pair),
* see `load_imm_2w_ori` and `load_imm_2w_addi` below.
* see `load_imm_2w_ori_forced` and `load_imm_2w_addi_forced` below.
*
* Statement-level (not expression-level): emits its own `asm volatile(...)`.
*/
@@ -411,9 +501,9 @@ enum { _BitOffsets = 0
} \
} while (0)
/* load_imm_2w_ori — force the `lui` + `ori` form regardless of lo16 sign.
/* load_imm_2w_ori_forced — force the `lui` + `ori` form regardless of lo16 sign.
* Use when you specifically need zero-extension in the lo half. */
#define load_imm_2w_ori(rt, imm) do { \
#define load_imm_2w_ori_forced(rt, imm) do { \
asm volatile( \
asm_words(load_ui((rt), u4_lo(imm)), \
or_i((rt), (rt), C_(U2,u4_hi(imm))) ) \
@@ -421,11 +511,11 @@ enum { _BitOffsets = 0
); \
} while (0)
/* load_imm_2w_addi — force the `lui` + `addi` form regardless of lo16 sign.
/* load_imm_2w_addi_forced — force the `lui` + `addi` form regardless of lo16 sign.
* Use when you know sign-extension is fine (e.g. lo16 is treated as
* signed downstream) and you want a smaller effective instruction
* (the assembler/MIPS hardware will sign-extend the imm16). */
#define load_imm_2w_addi(rt, imm) do { \
#define load_imm_2w_addi_forced(rt, imm) do { \
/*U4 _li2a_imm_ = (U4)(imm);*/ \
asm volatile(asm_words( \
lui_op((rt), u4_lo(imm)), \
@@ -495,10 +585,10 @@ enum { _BitOffsets = 0
* GPRs that the kernel treats as volatile (v0/v1/t0/t1/ra) plus the
* "memory" barrier. The register ids are passed through `rlit` so
* the R_*_Code `#define`s are stringified into "$N" at expansion time. */
#define clb_system rlit(R_V0), rlit(R_T0), rlit(R_T1), rlit(R_RA), clb_mem_drain
#define clbr_volatile_gprs rlit(R_V0), rlit(R_T0), rlit(R_T1), rlit(R_RA), clb_mem_drain
#define asm_mips_flush_icache() asm volatile( asm_words( \
add_ui(rstack_ptr, rstack_ptr, -8) \
add_ui(rstack_ptr, rstack_ptr, -MipsStackAlignment) \
, store_word(rret_addr, rstack_ptr, 4) \
, add_ui(rret_0, rdiscard, bios_flushcache) \
, add_ui(rtmp_0, rdiscard, bios_table_addr) \
@@ -506,5 +596,5 @@ enum { _BitOffsets = 0
, nop \
, load_word(rret_addr, rstack_ptr, 4) \
, jump_reg(rret_addr) \
, add_ui(rstack_ptr, rstack_ptr, 8) \
) asm_clobber: clb_system )
, add_ui(rstack_ptr, rstack_ptr, MipsStackAlignment) \
) asm_clobber: clbr_volatile_gprs )
+51
View File
@@ -0,0 +1,51 @@
/* ============================================================================
* duffle DSL — MIPS Vendor Mnemonics (opt-in)
* ============================================================================
*
* Provides the textbook MIPS assembly mnemonics as thin aliases to the
* canonical duffle macros in mips.h. The duffle names are primary; this
* header is for users who prefer the textbook mnemonics.
*
* USAGE: #include "duffle/mips_vendor_sym.h" // after mips.h
*
* Mapping (vendor -> duffle):
* Shift family:
* sll -> shift_lleft (shift left logical)
* srl -> shift_lright (shift right logical)
* sra -> shift_aright (shift right arithmetic)
* (no sllv/srlv/srav; the shift macros take a literal shamt)
*
* Jump family (1-arg / implicit-rd forms):
* jr -> jump_reg (jump register)
* j -> jump (jump to immediate address)
* jal -> call_addr (jump-and-link to immediate address)
* jalr -> call_reg (jump-and-link to register, default $ra)
* (for the 2-arg `jalr rs, rd`, use `jump_link(rs, rd)` directly)
*
* The vendor mnemonics are NOT registered with the duffle word-count
* metadata (tape_atom.metadata.h). They expand to the duffle canonical
* macros which DO have word-count entries. Verification: V2 (objdump
* byte-identical) holds.
*
* ============================================================================ */
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "mips.h"
#endif
#ifndef DUFFLE_MIPS_VENDOR_SYM_H
#define DUFFLE_MIPS_VENDOR_SYM_H
/* Shift family */
#define sll shift_lleft
#define srl shift_lright
#define sra shift_aright
/* Jump family (1-arg / implicit-$ra forms) */
#define jr jump_reg
#define j jump
#define jal call_addr
#define jalr call_reg
#endif
+11 -11
View File
@@ -44,7 +44,7 @@ internal MipsAtom_(rbind_cube_tri) {
load_word(R_FaceCursor, R_TapePtr, O_(Binds_CubeTri,FaceCursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_CubeTri,VertBase)),
load_word(R_OtBase, R_TapePtr, O_(Binds_CubeTri,OtBase)),
add_ui_1( R_TapePtr, S_(Binds_CubeTri)),
add_ui_self( R_TapePtr, S_(Binds_CubeTri)),
// Note(Ed): This entire thing is argument shuffle?
// TODO(Ed): Eliminate
mac_yield()
@@ -73,17 +73,17 @@ MipsAtom_(cube_tri) {
/* ── 2. Load V0, V1, V2 into GTE ────────────────────────────────────── */
/* V0 = verts[face->x] */
shift_ll(R_AT, R_T0, 3), add_u(R_AT, R_AT, R_VertBase),
shift_lleft(R_AT, R_T0, 3), add_u(R_AT, R_AT, R_VertBase),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0),
/* V1 = verts[face->y] */
shift_ll(R_AT, R_T1, 3), add_u(R_AT, R_AT, R_VertBase),
shift_lleft(R_AT, R_T1, 3), add_u(R_AT, R_AT, R_VertBase),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1),
/* V2 = verts[face->z] */
shift_ll(R_AT, R_T2, 3), add_u(R_AT, R_AT, R_VertBase),
shift_lleft(R_AT, R_T2, 3), add_u(R_AT, R_AT, R_VertBase),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2),
@@ -130,7 +130,7 @@ MipsAtom_(cube_tri) {
store_word(R_AT, R_PrimCursor, 28),
/* ── 7. Load V3 = verts[face->w] into V0 ─────────────────────────────── */
shift_ll(R_AT, R_T3, 3), add_u(R_AT, R_AT, R_VertBase),
shift_lleft(R_AT, R_T3, 3), add_u(R_AT, R_AT, R_VertBase),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0),
@@ -147,7 +147,7 @@ MipsAtom_(cube_tri) {
/* ── 10. Bounds check OTZ < 2048 ─────────────────────────────────────── */
add_ui( R_AT, R_0, 2048),
slt_u( R_AT, R_T1, R_AT),
set_lt_u( R_AT, R_T1, R_AT),
branch_equal(R_AT, R_0, 13), /* Skip 13 → land at add_ui(R_FaceCur,...) */
nop, /* BD slot */
@@ -179,7 +179,7 @@ MipsAtom_(rbind_floor_tri) {
load_word(R_FaceCursor, R_TapePtr, O_(Binds_FloorTri,FaceCursor)),
load_word(R_VertBase, R_TapePtr, O_(Binds_FloorTri,VertBase)),
load_word(R_OtBase, R_TapePtr, O_(Binds_FloorTri,OtBase)),
add_ui_1( R_TapePtr, S_(Binds_FloorTri)),
add_ui_self( R_TapePtr, S_(Binds_FloorTri)),
mac_yield()
};
@@ -209,17 +209,17 @@ MipsAtom_(floor_tri) {
nop, nop, gte_mf(R_T1, C2_OTZ),
/* Bounds Check OTZ < 2048 (Branch forward to skip insertion) */
add_ui( R_AT, R_0, OrderingTbl_Len),
slt_u( R_AT, R_T1, R_AT),
set_lt_u( R_AT, R_T1, R_AT),
branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)),
nop,
/* Insert into Ordering Table Linked List */
mac_insert_ot_tag(R_T1, 0x0400),
add_ui_1(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
add_ui_self(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
// Note(Ed): No bounds checking, should be checked before atom runs.
/* Advance Input Cursor & Yield (Both branch targets land here) */
atom_label(floor_tri_exit)
add_ui_1(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
add_ui_self(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
mac_yield()
};
@@ -233,7 +233,7 @@ typedef Struct_(Binds_SyncPrimitiveArena) { U4 used; U4 cursor; };
internal MipsAtom_(sync_primitive_arena) {
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,used)),
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,cursor)),
add_ui_1( R_TapePtr, S_(Binds_SyncPrimitiveArena)),
add_ui_self( R_TapePtr, S_(Binds_SyncPrimitiveArena)),
/* Calculate byte offset and store directly back to RAM */
sub_u( R_T0, R_PrimCursor, R_T0), // R_T0 = R_PrimCursor - binds.cursor
store_word(R_T0, R_AT, 0), // R_AT[0] = R_T0
+13 -4
View File
@@ -10,22 +10,31 @@
#define WORD_COUNT(name, count) enum { words_##name = (count) };
WORD_COUNT(nop, 1)
WORD_COUNT(load_upper_i, 1)
WORD_COUNT(jump_reg, 1)
WORD_COUNT(jump_link, 1)
WORD_COUNT(call_reg, 1)
WORD_COUNT(call_addr, 1)
WORD_COUNT(branch_le_zero, 1)
WORD_COUNT(branch_equal, 1)
WORD_COUNT(add_ui, 1)
WORD_COUNT(slt_u, 1)
WORD_COUNT(set_lt_u, 1)
WORD_COUNT(set_lt_s, 1)
WORD_COUNT(set_lt_si, 1)
WORD_COUNT(set_lt_ui, 1)
WORD_COUNT(load_ui, 1)
WORD_COUNT(load_word, 1)
WORD_COUNT(load_half_u, 1)
WORD_COUNT(store_word, 1)
WORD_COUNT(add_ui_1, 1)
WORD_COUNT(add_ui_self, 1)
WORD_COUNT(add_u_self, 1)
WORD_COUNT(add_u, 1)
WORD_COUNT(or_i, 1)
WORD_COUNT(or_u, 1)
WORD_COUNT(shift_ll, 1)
WORD_COUNT(shift_lr, 1)
WORD_COUNT(shift_lleft, 1)
WORD_COUNT(shift_lright, 1)
WORD_COUNT(shift_aright, 1)
WORD_COUNT(mask_upper, 2)
WORD_COUNT(gte_mf, 1)
WORD_COUNT(gte_mt, 1)
WORD_COUNT(gte_ct, 1)