diff --git a/code/duffle/atom_dsl.h b/code/duffle/atom_dsl.h index 932fe4f..564c424 100644 --- a/code/duffle/atom_dsl.h +++ b/code/duffle/atom_dsl.h @@ -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 * diff --git a/code/duffle/gte.h b/code/duffle/gte.h index 0bb332b..ba31f6c 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -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 diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index ae58d8b..7126dbd 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -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), diff --git a/code/duffle/mips.h b/code/duffle/mips.h index 0fa91ad..3ba93b5 100644 --- a/code/duffle/mips.h +++ b/code/duffle/mips.h @@ -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 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 ) diff --git a/code/duffle/mips_vendor_sym.h b/code/duffle/mips_vendor_sym.h new file mode 100644 index 0000000..e481486 --- /dev/null +++ b/code/duffle/mips_vendor_sym.h @@ -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 diff --git a/code/gte_hello/hello_gte_tape.c b/code/gte_hello/hello_gte_tape.c index 9674038..a92a4d4 100644 --- a/code/gte_hello/hello_gte_tape.c +++ b/code/gte_hello/hello_gte_tape.c @@ -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 diff --git a/code/gte_hello/tape_atom.metadata.h b/code/gte_hello/tape_atom.metadata.h index a5c118b..da4cf5b 100644 --- a/code/gte_hello/tape_atom.metadata.h +++ b/code/gte_hello/tape_atom.metadata.h @@ -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)