3 Commits
Author SHA1 Message Date
ed 602a0b46d8 Still learning/de-obfuscating 2026-07-08 21:17:16 -04:00
ed 74f390c3b1 Reviewing post-dsl refactors, more pseudo instructions 2026-07-08 17:14:11 -04:00
ed 5e7da32387 Adjustments to gp docs 2026-07-08 13:38:25 -04:00
8 changed files with 288 additions and 163 deletions
+4 -4
View File
@@ -99,10 +99,10 @@
#define Struct_(symbol) struct symbol TSet_(symbol); struct symbol
#define Union_(symbol) union symbol TSet_(symbol); union symbol
#define Opt_(proc) Struct_(tmpl(Opt,proc))
#define opt_(symbol, ...) (tmpl(Opt,symbol)){__VA_ARGS__}
#define Ret_(proc) Struct_(tmpl(Ret,proc))
#define ret_(proc) tmpl(Ret,proc) proc
#define Opt_(proc) Struct_(tmpl(Opt,proc))
#define opt_(symbol, ...) (tmpl(Opt,symbol)){__VA_ARGS__}
#define Ret_(proc) Struct_(tmpl(Ret,proc))
#define ret_(proc) tmpl(Ret,proc) proc
// Using Byte-Width convention for the fundamental types.
typedef __UINT8_TYPE__ TSet_(U1);
+165 -64
View File
@@ -46,9 +46,28 @@
* 0x1F800000+. GP0 (offset 0x10) is the data port (commands + params).
* GP1 (offset 0x14) is the control port (status, ctrl writes).
* ============================================================================ */
/* IO base address (KSEG2 0x1F800000+ for the I/O register region).
* The 16-bit upper half `IO_BASE_ADDR_HI16` is the form used by
* tape-side macros that pin a register to hold the IO base and access
* ports via offsets — `lui $reg, 0x1F80` (1 word) then `sw $data,
* GPIO_PORT*_OFFSET($reg)` (1 word). Mirrors the `IO_BASE_ADDR equ
* 0x1F80` + `gpio_port0 equ 0x1810` pattern from graphics_hello/gp.s.
*
* See lottes_tape.h `R_GpIoBase` + `mac_gp0_send_imm` for the
* wave-context form that composes these primitives. */
enum {
HW_GP0_ADDR = 0x1F801810, /* GPU data port (commands + parameters) */
HW_GP1_ADDR = 0x1F801814, /* GPU control port (status, ctrl writes) */
IO_BASE_ADDR = 0x1F800000, /* full 32-bit I/O region base */
IO_BASE_ADDR_HI16 = 0x1F80, /* fits in a single `lui $reg, 0x1F80` */
/* Offsets from IO_BASE_ADDR to each port. Used by tape-side macros
* that pin a register to IO_BASE_ADDR and access ports via offsets:
* sw $data, GPIO_PORT0_OFFSET($io_base) ; write GP0
* sw $data, GPIO_PORT1_OFFSET($io_base) ; write GP1 */
GPIO_PORT0_OFFSET = 0x1810,
GPIO_PORT1_OFFSET = 0x1814,
HW_GP0_ADDR = (IO_BASE_ADDR_HI16 << 16) | GPIO_PORT0_OFFSET,
HW_GP1_ADDR = (IO_BASE_ADDR_HI16 << 16) | GPIO_PORT1_OFFSET,
};
#define HW_GP0 C_(U4 V_*, HW_GP0_ADDR)
@@ -67,7 +86,7 @@ enum {
* so the encoder in §10.4 can reference them by name. NO macro body
* past this point uses a raw shift or raw mask — every shift/width/mask
* is named here, named once. Mirrors the OPCODE_SHIFT / RS_SHIFT /
* REG_MASK convention from mips.h lines 276-293.
* REG_MASK convention from mips.h.
* ============================================================================ */
enum {
gp0_cmd_Nop = 0x00,
@@ -101,13 +120,22 @@ enum {
gp0_cmd_tile_8 = 0x68,
gp0_cmd_tile_16 = 0x70,
/* State setters (not drawing primitives; set render context).
* Per PSX-SPX graphicsprocessingunitgpu.md §"GP0 Other Commands". */
gp0_cmd_DrawModeSetting = 0xE1, /* TPage / draw-mode (semi-trans, dither, etc.) */
gp0_cmd_SetTextureWindow = 0xE2,
gp0_cmd_SetDrawArea_TopLeft = 0xE3,
gp0_cmd_SetDrawArea_BotRight = 0xE4,
gp0_cmd_SetDrawOffset = 0xE5,
gp0_cmd_SetMaskBit = 0xE6,
/* bitfield shifts / widths / masks ----
*
* Generic GP0/GP1 command byte (upper 8 bits of every word sent
* to either port). Used by `enc_gp0_cmd(cmd)` and friends below. */
gp0_cmd_shift = 24,
gp0_cmd_width = 8,
gp0_cmd_mask = 0xFF,
gp0_cmd_shift = 24,
gp0_cmd_width = 8,
gp0_cmd_mask = 0xFF,
/* Color word layout (lives in Poly_F3.color, Poly_G4.c0..c3, etc.):
* bits 31..24 = command byte
@@ -126,9 +154,8 @@ enum {
*
* Layer 1.5 encoders take one field's value, mask it to its own width,
* and shift it to its own position. Mirrors `enc_op` / `enc_rs` /
* `enc_rt` in mips.h lines 295-301 and `enc_gte_sf` / `enc_gte_mx` in
* gte.h lines 342-347. Layer-2 composite encoders OR the per-field
* encoders together; layer-3 semantic macros delegate to the composites.
* `enc_rt` in mips.h and `enc_gte_sf` / `enc_gte_mx` in gte.h. Layer-2 composite encoders
* OR the per-field encoders together; layer-3 semantic macros delegate to the composites.
* No raw shifts or magic numbers in any macro body below this point.
* ============================================================================ */
@@ -148,7 +175,7 @@ enum {
/* ---- Layer 3: semantic GP0 word builders ---- */
/* Pre-baked color+command words for all 8 polygon variants.
* Mirrors `load_word` / `add_ui` / `jump_reg` style in mips.h lines 340-388. */
* Mirrors `load_word` / `add_ui` / `jump_reg` style in mips.h. */
#define gp0_word_poly_f3(r,g,b) enc_color_word(gp0_cmd_poly_f3, (r),(g),(b))
#define gp0_word_poly_ft3(r,g,b) enc_color_word(gp0_cmd_poly_ft3, (r),(g),(b))
#define gp0_word_poly_g3(r,g,b) enc_color_word(gp0_cmd_poly_g3, (r),(g),(b))
@@ -182,11 +209,11 @@ enum {
gp1_cmd_HorizontalDisplayRange = 0x06,
gp1_cmd_VerticalDisplayRange = 0x07,
gp1_cmd_DisplayMode = 0x08,
gp1_cmd_SetTextureWindow = 0x0E,
gp1_cmd_SetDrawAreaTopLeft = 0xE0,
gp1_cmd_SetDrawAreaBottomRight = 0xE1,
gp1_cmd_SetDrawOffset = 0xE2,
gp1_cmd_SetMaskBit = 0xE3,
/* Note: GP1 only has commands 0x00..0x08.
* The state-setter commands (SetTextureWindow, * SetDrawArea*,
* SetDrawOffset, SetMaskBit) live in the GP0 enum as * 0xE1..0xE6.
* DrawArea word builders are below as GP0s * macros
* (since they emit GP0 commands). */
/* ---- Display-mode payload flags (per PSX-SPX §"GP1 Display Mode").
* Bit positions match the encoder shifts below; values are the
@@ -208,38 +235,42 @@ enum {
gp1_disp_interlace_shift = 5, gp1_disp_interlace_width = 1, gp1_disp_interlace_mask = 0x1,
/* GP1 horizontal display range: bits 0..11 = X2, bits 12..23 = X1 */
gp1_hrange_x1_shift = 12, gp1_hrange_x1_width = 12, gp1_hrange_x1_mask = 0xFFF,
gp1_hrange_x2_shift = 0, gp1_hrange_x2_width = 12, gp1_hrange_x2_mask = 0xFFF,
gp1_hrange_x1_shift = 12, gp1_hrange_x1_width = 12, gp1_hrange_x1_mask = 0xFFF,
gp1_hrange_x2_shift = 0, gp1_hrange_x2_width = 12, gp1_hrange_x2_mask = 0xFFF,
/* GP1 vertical display range: bits 0..9 = Y2, bits 10..19 = Y1 */
gp1_vrange_y1_shift = 10, gp1_vrange_y1_width = 10, gp1_vrange_y1_mask = 0x3FF,
gp1_vrange_y2_shift = 0, gp1_vrange_y2_width = 10, gp1_vrange_y2_mask = 0x3FF,
gp1_vrange_y1_shift = 10, gp1_vrange_y1_width = 10, gp1_vrange_y1_mask = 0x3FF,
gp1_vrange_y2_shift = 0, gp1_vrange_y2_width = 10, gp1_vrange_y2_mask = 0x3FF,
/* GP1 draw area (top-left or bottom-right): bits 0..9 = X, bits 10..19 = Y
* (10-bit signed — caller pre-signs and masks with the named mask) */
gp1_draw_x_shift = 0, gp1_draw_x_width = 10, gp1_draw_x_mask = 0x3FF,
gp1_draw_y_shift = 10, gp1_draw_y_width = 10, gp1_draw_y_mask = 0x3FF,
gp1_draw_x_shift = 0, gp1_draw_x_width = 10, gp1_draw_x_mask = 0x3FF,
gp1_draw_y_shift = 10, gp1_draw_y_width = 10, gp1_draw_y_mask = 0x3FF,
};
/* ---- Layer 1.5: GP1 per-field encoders ---- */
#define enc_gp1_disp_hres(h) (((h) & gp1_disp_hres_mask) << gp1_disp_hres_shift)
#define enc_gp1_disp_vres(v) (((v) & gp1_disp_vres_mask) << gp1_disp_vres_shift)
#define enc_gp1_disp_color(c) (((c) & gp1_disp_color_mask) << gp1_disp_color_shift)
#define enc_gp1_disp_interlace(i) (((i) & gp1_disp_interlace_mask) << gp1_disp_interlace_shift)
#define enc_gp1_disp_hres(h) (((h) & gp1_disp_hres_mask) << gp1_disp_hres_shift)
#define enc_gp1_disp_vres(v) (((v) & gp1_disp_vres_mask) << gp1_disp_vres_shift)
#define enc_gp1_disp_color(c) (((c) & gp1_disp_color_mask) << gp1_disp_color_shift)
#define enc_gp1_disp_interlace(i) (((i) & gp1_disp_interlace_mask << gp1_disp_interlace_shift)
#define enc_gp1_hrange_x1(x1) (((x1) & gp1_hrange_x1_mask) << gp1_hrange_x1_shift)
#define enc_gp1_hrange_x2(x2) (((x2) & gp1_hrange_x2_mask) << gp1_hrange_x2_shift)
#define enc_gp1_vrange_y1(y1) (((y1) & gp1_vrange_y1_mask) << gp1_vrange_y1_shift)
#define enc_gp1_vrange_y2(y2) (((y2) & gp1_vrange_y2_mask) << gp1_vrange_y2_shift)
#define enc_gp1_draw_x(x) (((x) & gp1_draw_x_mask) << gp1_draw_x_shift)
#define enc_gp1_draw_y(y) (((y) & gp1_draw_y_mask) << gp1_draw_y_shift)
#define enc_gp1_hrange_x1(x1) (((x1) & gp1_hrange_x1_mask) << gp1_hrange_x1_shift)
#define enc_gp1_hrange_x2(x2) (((x2) & gp1_hrange_x2_mask) << gp1_hrange_x2_shift)
#define enc_gp1_vrange_y1(y1) (((y1) & gp1_vrange_y1_mask) << gp1_vrange_y1_shift)
#define enc_gp1_vrange_y2(y2) (((y2) & gp1_vrange_y2_mask) << gp1_vrange_y2_shift)
#define enc_gp1_draw_x(x) (((x) & gp1_draw_x_mask) << gp1_draw_x_shift)
#define enc_gp1_draw_y(y) (((y) & gp1_draw_y_mask) << gp1_draw_y_shift)
/* ---- Layer 2: GP1 composite encoders ---- */
#define enc_gp1_disp_mode_word(h, v, c, i) (enc_gp0_cmd(gp1_cmd_DisplayMode) | enc_gp1_disp_hres(h) | enc_gp1_disp_vres(v) | enc_gp1_disp_color(c) | enc_gp1_disp_interlace(i))
#define enc_gp1_hrange_word(x1, x2) (enc_gp0_cmd(gp1_cmd_HorizontalDisplayRange) | enc_gp1_hrange_x1(x1) | enc_gp1_hrange_x2(x2))
#define enc_gp1_vrange_word(y1, y2) (enc_gp0_cmd(gp1_cmd_VerticalDisplayRange) | enc_gp1_vrange_y1(y1) | enc_gp1_vrange_y2(y2))
#define enc_gp1_draw_area_tl_word(x, y) (enc_gp0_cmd(gp1_cmd_SetDrawAreaTopLeft) | enc_gp1_draw_x(x) | enc_gp1_draw_y(y))
#define enc_gp1_draw_area_br_word(x, y) (enc_gp0_cmd(gp1_cmd_SetDrawAreaBottomRight) | enc_gp1_draw_x(x) | enc_gp1_draw_y(y))
/* ---- Layer 2: GP0 state-setter composite encoders ----
* GP0(0xE3) SetDrawArea top-left and GP0(0xE4) SetDrawArea bottom-right
* both use the same X/Y 10-bit signed payload as GP1 DisplayRange. */
#define enc_gp0_draw_area_tl_word(x, y) (enc_gp0_cmd(gp0_cmd_SetDrawArea_TopLeft) | enc_gp1_draw_x(x) | enc_gp1_draw_y(y))
#define enc_gp0_draw_area_br_word(x, y) (enc_gp0_cmd(gp0_cmd_SetDrawArea_BotRight) | enc_gp1_draw_x(x) | enc_gp1_draw_y(y))
/* ---- Layer 3: GP1 semantic word builders ---- */
#define gp1_word_display_enable(on) (enc_gp0_cmd(gp1_cmd_DisplayEnable) | ((on) & 1))
@@ -250,10 +281,74 @@ enum {
#define gp1_word_horizontal_range(x1, x2) enc_gp1_hrange_word((x1), (x2))
#define gp1_word_vertical_range(y1, y2) enc_gp1_vrange_word((y1), (y2))
/* ---- Layer 3: GP0 state-setter semantic word builders ---- */
/* DrawArea: top-left = (X, Y), bottom-right = (X, Y) — X/Y in 10-bit signed.
* Caller is responsible for sign-conversion before passing in. */
#define gp1_word_draw_area_top_left(x, y) enc_gp1_draw_area_tl_word((x), (y))
#define gp1_word_draw_area_bottom_right(x, y) enc_gp1_draw_area_br_word((x), (y))
#define gp0_word_draw_area_top_left(x, y) enc_gp0_draw_area_tl_word((x), (y))
#define gp0_word_draw_area_bottom_right(x, y) enc_gp0_draw_area_br_word((x), (y))
/* ============================================================================
* Pre-baked GPU state words
* ============================================================================
*
* Common command words for boot-time GPU init and standard
* display configurations. Each one is a pure compile-time integer
* constant ready to drop into a `.word` directive.
*
* These are the equivalents of the `gp_HorizontalDisplayRange_3168_608`,
* `gp_VerticalDisplayRange_264_24`, `gp_DisplayMode_320x240_15bit_NTSC`,
* `gp_SetDrawMode_DrawAllowed`, `gp_DMA_*` `.equ`s from the pre-rewrite
* gp.h / graphics_hello/gp.s, rebuilt using the layer-cake encoders so
* no magic numbers appear in any body.
* ============================================================================ */
/* ---- Display enable (1-bit payload on DisplayEnable cmd) ---- */
#define gp1_word_display_enabled enc_gp0_cmd_word(gp1_cmd_DisplayEnable)
#define gp1_word_display_disabled (enc_gp0_cmd_word(gp1_cmd_DisplayEnable) | 1)
/* ---- DMA direction (2-bit payload on DMADirection cmd 0x04) ---- */
enum {
gp1_dma_dir_Off = 0,
gp1_dma_dir_FIFO = 1,
gp1_dma_dir_CPU_to_GPU = 2,
gp1_dma_dir_GPUREAD_to_CPU = 3,
};
#define gp1_word_dma_direction(dir) (enc_gp0_cmd(gp1_cmd_DMADirection) | ((dir) & 0x3))
/* ---- Standard display ranges (NTSC + PAL pre-baked) ---- */
/* Horizontal range values are in video clock units (8 units/pixel); vertical range values are scanline numbers. */
enum {
/* NTSC horizontal range: X1=608, X2=3168 */
gp1_hrange_NTSC_x1 = 0x260,
gp1_hrange_NTSC_x2 = 0xC60,
/* PAL horizontal range (same as NTSC for most CRTs) */
gp1_hrange_PAL_x1 = 0x260,
gp1_hrange_PAL_x2 = 0xC60,
/* NTSC vertical range: Y1=24, Y2=264 */
gp1_vrange_NTSC_y1 = 24,
gp1_vrange_NTSC_y2 = 264,
/* PAL vertical range: Y1=24, Y2=504 */
gp1_vrange_PAL_y1 = 24,
gp1_vrange_PAL_y2 = 504,
};
#define gp1_word_horizontal_range_ntsc enc_gp1_hrange_word(gp1_hrange_NTSC_x1, gp1_hrange_NTSC_x2)
#define gp1_word_horizontal_range_pal enc_gp1_hrange_word(gp1_hrange_PAL_x1, gp1_hrange_PAL_x2)
#define gp1_word_vertical_range_ntsc enc_gp1_vrange_word(gp1_vrange_NTSC_y1, gp1_vrange_NTSC_y2)
#define gp1_word_vertical_range_pal enc_gp1_vrange_word(gp1_vrange_PAL_y1, gp1_vrange_PAL_y2)
/* ---- Draw-mode setting (TPage / draw-area allowance) ---- */
/* The pre-baked "drawing enabled" word is the standard post-init state. */
enum {
gp0_DrawMode_DrawToDispBit = 10,
};
#define gp0_word_draw_mode_drawing_allowed (enc_gp0_cmd(gp0_cmd_DrawModeSetting) | (1 << gp0_DrawMode_DrawToDispBit))
/* ---- DrawArea pre-baked at origin (0,0) and full screen (320x240) ---- */
#define gp0_word_draw_area_top_left_origin enc_gp0_draw_area_tl_word(0, 0)
#define gp0_word_draw_area_bottom_right_320x240 enc_gp0_draw_area_br_word(320, 240)
#define gp0_word_draw_area_bottom_right_640x480 enc_gp0_draw_area_br_word(640, 480)
#pragma endregion GPU Ports & Commands
@@ -311,12 +406,7 @@ typedef Struct_(PolyTag) {
/* DSL cast convention: every cast uses `C_()`, every pointer qualifier
* is `R_` (restrict) or `V_` (volatile). No raw C-style casts. RHS values
* are assumed to be `U4` — caller passes a `U4` directly.
*
* IMPORTANT: do NOT name an arg the same as a struct member being
* accessed in the body — preprocessor substitution would replace the
* member name with the caller's value expression, yielding `->expr`
* which is a parse error. Use `v` (value) for the arg instead. */
* are assumed to be `U4` — caller passes a `U4` directly. */
#define set_len(tag,v) (C_(PolyTag_R,tag)->len = u4_(v))
#define set_addr(tag,v) (C_(PolyTag_R,tag)->addr = u4_(v))
/* `set_code` is no longer in the new PolyTag design — the code byte lives
@@ -450,12 +540,6 @@ typedef Struct_(Poly_GT4) {
* bit 10 = drawing to display area (1 bit)
* bit 11 = texture disable (1 bit)
* bits 12..31 = reserved (zero)
*
* The previous version of this file had `gp0_tpage_semi_trans_shift
* = 7`, which is WRONG — semi-transparency lives at bits 5..6 (after Y
* at bit 4). Likewise the prior `gp0_tpage_clut_depth_shift = 12` and
* `gp0_tpage_y_flip_bit = 15` referenced fields that don't exist on the
* TPage word. See design.md §10.9 and PSX-SPX §"Rendering Attributes".
* ============================================================================ */
enum {
/* ---- Layer 1: TPage bitfield shifts / widths / masks ---- */
@@ -480,8 +564,7 @@ enum {
gp0_tpage_semi_trans_sub = 0x3,
};
/* ---- Layer 1.5: TPage per-field encoders. Mirrors enc_gte_sf/mx/v in
* gte.h lines 342-347. ---- */
/* ---- Layer 1.5: TPage per-field encoders. Mirrors enc_gte_sf/mx/v in gte.h. ---- */
#define enc_gp0_tpage_x(x) (((x) & gp0_tpage_x_mask) << gp0_tpage_x_shift)
#define enc_gp0_tpage_y(y) (((y) & gp0_tpage_y_mask) << gp0_tpage_y_shift)
#define enc_gp0_tpage_semi_trans(s) (((s) & gp0_tpage_semi_trans_mask) << gp0_tpage_semi_trans_shift)
@@ -490,8 +573,7 @@ enum {
#define enc_gp0_tpage_draw_to_disp(d) (((d) & gp0_tpage_draw_to_disp_mask) << gp0_tpage_draw_to_disp_shift)
#define enc_gp0_tpage_tex_disable(t) (((t) & gp0_tpage_tex_disable_mask) << gp0_tpage_tex_disable_shift)
/* ---- Layer 2: TPage composite encoder. Mirrors enc_gte_cmdw in gte.h
* line 350. ---- */
/* ---- Layer 2: TPage composite encoder. Mirrors enc_gte_cmdw in gte.h ---- */
#define enc_gp0_tpage_word(x, y, semi_trans, color_depth, dither, draw_to_disp, tex_disable) \
(enc_gp0_tpage_x(x) \
| enc_gp0_tpage_y(y) \
@@ -512,19 +594,12 @@ typedef Struct_(TexturePage) { U4 raw; };
/* ============================================================================
* CLUT (Color Look-Up Table) semantics
* ============================================================================
*
*
* CLUT is loaded into VRAM by sending a GP0 command whose payload is:
* bits 0..5 = Y in 16-px units (palette row)
* bits 6..14 = X in 16-px units (palette column)
* bits 15..23 = reserved (zero)
* bits 24..31 = command byte — 0x20 (4bpp load) or 0x25 (8bpp load)
*
* The previous version used `depth_4bpp ? 0 : 5` as the lower-5 bits
* of the cmd byte — that's an opaque ternary that hides which opcode
* is being sent. The two cmd-byte values are now named; one macro per
* depth. Mirrors the named-opcode rule from mips.h lines 188-271 and
* the `gte_cmd_rtpt` / `gte_cmd_nclip` named-opcode pattern from
* gte.h lines 209-214.
* ============================================================================ */
enum {
/* ---- Layer 1: CLUT bitfield shifts / widths / masks ---- */
@@ -600,12 +675,38 @@ typedef Struct_(TIM_SectionHeader) {
#pragma region Tape-Side Macros
/* ============================================================================
* Tape-side macro components
* Tape-side GPU operations (NOT in this header)
* ============================================================================
*
* TODO: mac_gp0_send — write a 32-bit GPU command word to HW_GP0 from
* within an atom body. Requires placeholder-pun on a runtime GPR holding
* the port address.
* No `mac_gp0_send` or related macros live in gp.h. Rationale: the
* Lottes tape model uses OT-DMA for primitive submission, so atom bodies
* write to main RAM (the OT/primitive buffer) and to GTE state — never
* directly to the GPU ports at 0x1F801810 / 0x1F801814. See
* `mac_format_f3_color`, `mac_insert_ot_tag`, `mac_gte_store_f3` in
* lottes_tape.h for the patterns atom bodies actually use.
*
* If a feature need arises requires tape-side GPU port writes (e.g. DMA-kick to
* start GPU consumption of the OT, VBlank sync via GP1 status poll),
* the right home is `lottes_tape.h` alongside the rest of the `mac_*`
* family — the encoder infrastructure is already in place:
*
* 1. The caller pins a register to hold the IO base, e.g.
* register U4 r_io rgcc(R_T4) = IO_BASE_ADDR;
* The compiler emits `lui R_T4, IO_BASE_ADDR_HI16` outside the
* atom body (in the C prologue before tape_run).
*
* 2. The atom body uses `store_word(R_data, R_T4, GPIO_PORT0_OFFSET)`
* to write to GP0, and `store_word(R_data, R_T4, GPIO_PORT1_OFFSET)`
* to write to GP1. Both are preprocessor-encodable because R_T4 is
* a fixed register and the GPIO_PORT*_OFFSET constants fit in the
* `sw`'s 16-bit signed offset field. No placeholder-pun, no asm
* constraints, no hidden register choice. Same pattern as the
* old graphics_hello/hello_gp_routines.s `reg_io_offset`/`gcmd_push`
* convention.
*
* This mirrors the existing tape-side wave-context discipline: the
* caller binds the IO-base register via `rgcc()`, the macro assumes
* the binding is in effect, and the encoding falls out at preprocessor
* time. No additional GPU-domain macro layer required.
* ============================================================================ */
/* #define mac_gp0_send(r_gp_port, word) ... deferred */
#pragma endregion Tape-Side Macros
+55 -19
View File
@@ -284,26 +284,64 @@ enum {
};
enum { _C2_OPS_ = 0
, op_lwc2 = 0x32 /* Load Word to Coprocessor 2 (GTE) */
, op_swc2 = 0x3A /* Store Word from Coprocessor 2 (GTE) */
};
/* COP2 (GTE) Transfer Format: ctc2 rt, rd or cfc2 rt, rd
/* COP2 transfer sub-opcodes (5-bit field in the `rs` slot of enc_gte_tx).
*
* Spans the 2x2 {From, To} × {Data, Control} register classes that the
* GTE exposes:
*
* bit 1 (0x02): register class — 0 = data, 1 = control
* bit 2 (0x04): direction — 0 = read, 1 = write
*
* The values 0x00 (sub_mfc2) and 0x04 (sub_mtc2) are the same 5-bit
* numbers as the general MIPS `cop_mf` / `cop_mt` defined in mips.h
* (which target the data register file on any coprocessor). They are
* re-aliased here so the four-way table reads like the spec mnemonics
* (MFC2 / CFC2 / MTC2 / CTC2) and so the encoding lives next to its
* only consumer (this header).
*
* Vendor mnemonic aliases (gte_mfc2 / gte_mtc2 / gte_cfc2 / gte_ctc2)
* live in gte_vendor_sym.h. */
enum { _C2_TX_SUBS_ = 0
, sub_mfc2 = 0x00 /* MFC2: Move From Coprocessor 2 data reg */
, sub_cfc2 = 0x02 /* CFC2: Copy From Coprocessor 2 ctrl reg */
, sub_mtc2 = 0x04 /* MTC2: Move To Coprocessor 2 data reg */
, sub_ctc2 = 0x06 /* CTC2: Copy To Coprocessor 2 ctrl reg */
};
/* COP2 (GTE) Transfer Format: mfc2 / cfc2 / mtc2 / ctc2 rt, rd
* Layout: [op_cop2:6][sub:5][rt:5][rd:5][0:11]
* - sub: cop_mf (0x00) for cfc2, cop_mt (0x04) for ctc2
* - sub: one of sub_mfc2 / sub_cfc2 / sub_mtc2 / sub_ctc2
* - rt: GPR source/dest
* - rd: COP2 control register index (0..31) */
* - rd: COP2 register index (0..31):
* data class → C2_VXY0_Code..C2_LZCR_Code (gte_in_v0_xy..gte_math_accum2 aliases)
* ctrl class → gte_cr_RT11_Code..gte_cr_OFY_Code */
#define enc_gte_tx(sub, rt, rd) (enc_op(op_cop2) | enc_rs(sub) | enc_rt(rt) | enc_rd(rd))
// #define gte_mv_to_data_r(rt, rd) enc_gte_tx(cop_mt, (rt), (rd)) /* Move GPR (rt) to GTE Control Register (rd) */
// #define gte_mv_from_data_r(rt, rd) enc_gte_tx(cop_mf, (rt), (rd)) /* Move GTE Control Register (rd) to GPR (rt) */
/* GTE Data vs Control Register Transfers */
#define gte_mv_from_data_r(rt, rd) enc_gte_tx(0x00, (rt), (rd)) /* Move from GTE Data Reg (e.g. MAC0, OTZ) */
#define gte_mv_from_ctrl_r(rt, rd) enc_gte_tx(0x02, (rt), (rd)) /* Move from GTE Control Reg */
#define gte_mv_to_data_r(rt, rd) enc_gte_tx(0x04, (rt), (rd)) /* Move to GTE Data Reg (e.g. VXY0) */
#define gte_mv_to_ctrl_r(rt, rd) enc_gte_tx(0x06, (rt), (rd)) /* Move to GTE Control Reg (e.g. Matrices) */
/* GTE Data vs Control Register Transfers
*
* Each macro emits a single .word constant for one of MFC2/CFC2/MTC2/CTC2.
*
* `rd` is the C2 register index in the file the sub-opcode names:
* gte_mv_from_data_r / gte_mv_to_data_r → C2 data register file
* gte_mv_from_ctrl_r / gte_mv_to_ctrl_r → C2 ctrl register file
*
* Common pairs:
* gte_mv_from_data_r(R_T0, C2_MAC0) — read MAC0 into a GPR
* gte_mv_to_data_r (R_V0, C2_VXY0) — write GPR into VXY0
* gte_mv_to_ctrl_r (R_T0, gte_cr_RT11) — write GPR into rotation matrix
* gte_mv_from_ctrl_r(R_T0, gte_cr_OFX) — read screen-X offset */
#define gte_mv_from_data_r(rt, rd) enc_gte_tx(sub_mfc2, (rt), (rd)) /* Move From data reg */
#define gte_mv_from_ctrl_r(rt, rd) enc_gte_tx(sub_cfc2, (rt), (rd)) /* Copy From ctrl reg */
#define gte_mv_to_data_r(rt, rd) enc_gte_tx(sub_mtc2, (rt), (rd)) /* Move To data reg */
#define gte_mv_to_ctrl_r(rt, rd) enc_gte_tx(sub_ctc2, (rt), (rd)) /* Copy To ctrl reg */
/* COP2 Data Load (lwc2): `lwc2 rt, off(rs)`
* Layout: [op_lwc2:6][rs:5][rt:5][imm:16]
@@ -464,7 +502,6 @@ enum {
* (typically one of R_T4..R_T9 for the standard "3-pointer" pattern).
*
* The caller MUST bind `r_ptr` to that same GPR via a register variable:
*
* register V3_S2* p_in_12 __asm__("$12") = my_ptr;
* gte_load_v0(p_in_12, R_T4); // R_T4 = 12, base is $12
*
@@ -494,21 +531,21 @@ enum {
*
* The `asm_clobber(...)` helper from gcc_asm.h prepends the colon that
* starts the clobbers section. */
#define gte_load_v0(r_ptr, base) asm volatile( \
#define gte_load_v0(r_ptr, base) asm volatile( \
asm_words( gte_lw_v0_xy(base), gte_lw_v0_z(base) ) \
asm_rpins, r_use(r_ptr) \
asm_rpins, r_use(r_ptr) \
asm_clobber: rlit(R_V0), rlit(R_T0), rlit(R_T1), rlit(R_RA), clb_mem_drain \
)
#define gte_load_v1(r_ptr, base) asm volatile( \
#define gte_load_v1(r_ptr, base) asm volatile( \
asm_words( gte_lw_v1_xy(base), gte_lw_v1_z(base) ) \
asm_rpins, r_use(r_ptr) \
asm_rpins, r_use(r_ptr) \
asm_clobber: rlit(R_V0), rlit(R_T0), rlit(R_T1), rlit(R_RA), clb_mem_drain \
)
#define gte_load_v2(r_ptr, base) asm volatile( \
asm_words( gte_lw_v2_xy(base), gte_lw_v2_z(base) ) \
asm_rpins, r_use(r_ptr) \
#define gte_load_v2(r_ptr, base) asm volatile( \
asm_words( gte_lw_v2_xy(base), gte_lw_v2_z(base) ) \
asm_rpins, r_use(r_ptr) \
asm_clobber: rlit(R_V0), rlit(R_T0), rlit(R_T1), rlit(R_RA), clb_mem_drain \
)
@@ -563,7 +600,7 @@ enum {
#define gte_rtpt() \
asm volatile( \
asm_words( nop, nop, gte_cmdw_rtpt ) \
asm_clobber: clbr_volatile_gprs \
asm_clobber: clbr_volatile_gprs \
)
#define gte_rtpt_asm_str() \
@@ -635,7 +672,6 @@ enum {
* [RT_xx, RT_xy] | [RT_xz, pad] | ...).
*
* Generated MIPS (mirrors the source macro):
*
* lw $12, 0( %0 ) ; word 0
* lw $13, 4( %0 ) ; word 1
* ctc2 $12, $0 ; → C2_RT11
+42 -47
View File
@@ -44,14 +44,14 @@ MipsAtom_(tape_exit) { jump_reg(rret_addr), nop };
/* Generalized Tape Engine Runner */
FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; asm volatile(
asm_words(
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_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_self( R_SP, MipsStackAlignment) /* Deallocate stack space */
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_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_self(R_SP, MipsStackAlignment) /* Deallocate stack space */
)
asm_rpins, r_use(tp)
asm_clobber:
@@ -107,11 +107,11 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
, 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_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2)
/* Words: 11; Correctly inserts a primitive into the Ordering Table linked list */
#define mac_insert_ot_tag(r_otz, prim_length) \
shift_lleft( R_T1, r_otz, 2) /* T1 = r_otz * S_(U4) */ \
, add_u( R_T1, R_T1, R_OtBase) /* T1 = & OrderingTable[OTZ] */ \
#define mac_insert_ot_tag(r_otz, prim_type) \
shift_lleft( R_T1, r_otz, S_(U4)/2) /* T1 = r_otz * S_(U4) */ \
, add_u_self( 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) */ \
, load_upper_i(R_V0, (S_(prim_type)/S_(U4) - S_(PolyTag)/S_(U4)) << polytag_len_bits) /* V0 = S_(prim_type without tag field) */ \
, 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) */ \
@@ -123,10 +123,10 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli
* Args: _r, _g, _b are 8-bit RGB byte values (not raw 16-bit fields).
* Migrated from hello_gte_tape.c; takes RGB form per the Phase 3
* convention. */
#define mac_format_f3_color(_r, _g, _b) \
load_upper_i( R_AT, gp0_cmd_poly_f3 << 8 | (_b)) \
, or_i( R_AT, R_AT, ((_g) << 8) | (_r)) \
, store_word(R_AT, R_PrimCursor, O_(Poly_F3,color))
#define mac_format_f3_color(r,g,b) \
load_upper_i(R_AT, gp0_cmd_poly_f3 << 8 | (b)) \
, or_i_self( R_AT, ((g) << 8) | (r)) \
, store_word( R_AT, R_PrimCursor, O_(Poly_F3,color))
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3 */
#define mac_gte_store_f3() \
@@ -200,21 +200,17 @@ internal MipsAtom_(mips_flush_icache) {
typedef Struct_(Binds_SetGteWorld) {
U4 transform;
};
// TODO(Ed): Bugged, fix
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_self( R_TapePtr, S_(Binds_SetGteWorld)),
// TODO(Ed): Annotate magic offsets.
add_ui_self( R_TapePtr, S_(Binds_SetGteWorld)),
/* 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),
gte_mv_to_ctrl_r( R_T0, gte_cr_RT11), gte_mv_to_ctrl_r( R_T1, gte_cr_RT12),
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_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),
load_word(R_T0, R_T3, 0), load_word(R_T1, R_T3, 4),
gte_mv_to_ctrl_r(R_T0, gte_cr_RT11), gte_mv_to_ctrl_r(R_T1, gte_cr_RT12),
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_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()
};
@@ -228,25 +224,24 @@ internal MipsAtom_(diag_yield) { mac_yield() };
internal MipsAtom_(diag_color) {
store_word( R_0, R_T7, 0),
load_upper_i(R_AT, gp0_cmd_poly_f3 << 8 | 0xFF), /* High: MipsCode Poly_F3(0x20) + Color B:FF */
or_i( R_AT, R_AT, 0xFF00), /* Low: Color G:FF, R:00 (Cyan) */
or_i_self( R_AT, 0xFF00), /* Low: Color G:FF, R:00 (Cyan) */
store_word( R_AT, R_T7, 4),
/* Fake coordinates - Swapped winding order to prevent GPU culling! */
load_upper_i(R_AT, 0x0010), or_i(R_AT, R_AT, 0x0010), store_word(R_AT, R_T7, 8), /* (16, 16) */
load_upper_i(R_AT, 0x0050), or_i(R_AT, R_AT, 0x0010), store_word(R_AT, R_T7, 12), /* (80, 16) */
load_upper_i(R_AT, 0x0010), or_i(R_AT, R_AT, 0x0050), store_word(R_AT, R_T7, 16), /* (16, 80) */
load_upper_i(R_AT, 0x0010), or_i_self(R_AT, 0x0010), store_word(R_AT, R_T7, 8), /* (16, 16) */
load_upper_i(R_AT, 0x0050), or_i_self(R_AT, 0x0010), store_word(R_AT, R_T7, 12), /* (80, 16) */
load_upper_i(R_AT, 0x0010), or_i_self(R_AT, 0x0050), store_word(R_AT, R_T7, 16), /* (16, 80) */
add_ui( R_T1, R_0, 10),
shift_lleft(R_T1, R_T1, 2),
add_u( R_T1, R_T1, R_T6),
add_ui( R_T1, R_0, 10),
shift_lleft_self(R_T1, S_(U4)/2),
add_u_self( R_T1, R_T6),
load_word( R_AT, R_T1, 0),
load_upper_i(R_V0, 0x0400), // <--- Fills load delay slot!
load_upper_i(R_V0, (S_(Poly_F3)/S_(U4) - S_(PolyTag)/S_(U4)) << polytag_len_bits),
store_word( R_AT, R_T7, 0),
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),
shift_lleft(R_AT, R_T7, S_(polytag_len_bits)), shift_lright(R_AT, R_AT, S_(polytag_len_bits)),
or_u_self( R_AT, R_V0),
store_word( R_AT, R_T1, 0),
add_ui(R_T7, R_T7, 20),
@@ -264,20 +259,20 @@ internal MipsAtom_(diag_gte) {
/* Load Vertices into GTE */
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_mv_to_data_r( R_V0, C2_VXY0), gte_mv_to_data_r( R_V1, C2_VZ0),
gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0),
shift_lleft( 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_mv_to_data_r( R_V0, C2_VXY1), gte_mv_to_data_r( R_V1, C2_VZ1),
gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1),
shift_lleft( 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_mv_to_data_r( R_V0, C2_VXY2), gte_mv_to_data_r( R_V1, C2_VZ2),
gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2),
/* Run Math */
nop, nop, gte_cmdw_rtpt,
nop, nop, gte_cmdw_nclip,
nop, nop,
nop2, gte_cmdw_rtpt,
nop2, gte_cmdw_nclip,
nop2,
/* Advance Face Cursor and Yield */
add_ui(R_T4, R_T4, 8),
+7 -1
View File
@@ -355,6 +355,7 @@ enum { _BitOffsets = 0
#define load_u4 load_word
// Ergonomic add to the same register.
#define or_i_self(rt_rs, imm) enc_i(op_ori, (rt_rs), (rt_rs), (imm))
#define add_ui_self(rt_rs, imm) enc_i(op_addiu, (rt_rs), (rt_rs), (imm))
/* Logic Opcodes */
@@ -364,11 +365,15 @@ 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)
#define or_u_self(rd_rs, rt) enc_r(op_special, (rd_rs), (rt), (rd_rs), 0, fc_or)
/* 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_lleft_self(rd_rt, shamt) enc_r(op_special, R_0, (rd_rt), (rd_rt), (shamt), fc_sll)
#define mask_upper(rd, rt, shamt) shift_lleft(rd, rt, shamt), shift_lright(rd, rt, shamt)
/* jr rs — jump to address in rs. */
@@ -459,7 +464,8 @@ enum { _BitOffsets = 0
#define shift_amount(rd, rt, n) shift_lleft(rd, rt, n)
/* nop — canonical sll $0, $0, 0 */
#define nop shift_lleft(rdiscard, rdiscard, 0)
#define nop shift_lleft(rdiscard, rdiscard, 0)
#define nop2 nop, nop
#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))
-9
View File
@@ -63,14 +63,6 @@ U4 vsync(U4 mode) __asm__("VSync");
void draw_orderingtbl(U4* buf) __asm__("DrawOTag");
/* Primitive Handling Macros
* All primitive types (PolyTag, Poly_F3, Poly_F4, Poly_G3, Poly_G4,
* Poly_FT3, Poly_FT4, Poly_GT3, Poly_GT4) and the set_poly_* setters,
* set_len / set_addr / get_len / get_addr macros, and the
* orderingtbl_add_primitive(s) helpers all live in `duffle/gp.h`
* now (per the Phase 3 gp.h overhaul). This file no longer duplicates
* those definitions. */
typedef Struct_(Tile) {
U4 tag;
RGB8 color;
@@ -78,7 +70,6 @@ typedef Struct_(Tile) {
Rect_S2 rect;
};
/*
Linear Algebra
*/
+12 -18
View File
@@ -12,13 +12,6 @@
* (mac_format_f3_color takes _r, _g, _b byte values rather than raw
* 16-bit half-words). */
enum fack {
ah = gp0_cmd_poly_f3 << 8 | 0xFF,
};
void fk() {
(void*)ah;
}
#pragma endregion MACs
#pragma region Baked Atoms
@@ -35,7 +28,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_self( 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()
@@ -143,7 +136,7 @@ MipsAtom_(cube_tri) {
nop, /* BD slot */
/* ── 11. Insert into Ordering Table (length = 8 for Poly_G4) ─────────── */
mac_insert_ot_tag(R_T1, 0x0800), /* 0x0800 = 8 << 8 = length 8 in tag */
mac_insert_ot_tag(R_T1, Poly_G4), /* 0x0800 = 8 << 8 = length 8 in tag */
/* ── 12. Advance cursors & yield ─────────────────────────────────────── */
add_ui(R_PrimCursor, R_PrimCursor, 36), /* 9 words × 4 bytes */
@@ -170,7 +163,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_self( R_TapePtr, S_(Binds_FloorTri)),
add_ui_self( R_TapePtr, S_(Binds_FloorTri)),
mac_yield()
};
@@ -184,9 +177,9 @@ internal
MipsAtom_(floor_tri) {
mac_load_tri_indices(R_T0, R_T1, R_T2),
mac_load_tri_verts( R_T0, R_T1, R_T2),
nop, nop, gte_cmdw_rotate_translate_perspective_triple,
nop, nop, gte_cmdw_nclip,
nop, nop,
nop2, gte_cmdw_rotate_translate_perspective_triple,
nop2, gte_cmdw_nclip,
nop2,
/* Culling (Branch forward if Backface) */
gte_mv_from_data_r(R_T0, C2_MAC0),
nop, branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)),
@@ -195,16 +188,17 @@ MipsAtom_(floor_tri) {
// mac_format_f3_color(0x20FF, 0xFFFF), // works
mac_format_f3_color(0xFF, 0xFF, 0xFF), // RGB-form (R=FF, G=FF, B=FF = white)
mac_gte_store_f3(),
/* Calculate Depth */
nop, nop, gte_avg_sort_z3,
nop, nop, gte_mv_from_data_r(R_T1, C2_OTZ),
nop2, gte_avg_sort_z3,
nop2, gte_mv_from_data_r(R_T1, C2_OTZ),
/* Bounds Check OTZ < 2048 (Branch forward to skip insertion) */
add_ui( R_AT, R_0, OrderingTbl_Len),
set_lt_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),
mac_insert_ot_tag(R_T1, Poly_F3),
add_ui_self(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
// Note(Ed): No bounds checking, should be checked before atom runs.
@@ -224,7 +218,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_self( 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
+3 -1
View File
@@ -22,7 +22,6 @@ 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)
@@ -30,8 +29,11 @@ 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_i_self, 1)
WORD_COUNT(or_u, 1)
WORD_COUNT(or_u_self, 1)
WORD_COUNT(shift_lleft, 1)
WORD_COUNT(shift_lleft_self, 1)
WORD_COUNT(shift_lright, 1)
WORD_COUNT(shift_aright, 1)
WORD_COUNT(mask_upper, 2)