mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-07-12 20:31:25 -07:00
learning...
This commit is contained in:
@@ -206,7 +206,8 @@
|
||||
* writes at this granularity.
|
||||
*
|
||||
* ============================================================================*/
|
||||
#define tape_regs(...) (__VA_ARGS__)
|
||||
#define atom_reads(...) (__VA_ARGS__)
|
||||
#define atom_writes(...) (__VA_ARGS__)
|
||||
|
||||
/* ============================================================================
|
||||
* ATOM ANNOTATION MACROS
|
||||
|
||||
@@ -189,22 +189,6 @@ internal MipsAtom_(mips_flush_icache) {
|
||||
, mac_yield()
|
||||
};
|
||||
|
||||
typedef Struct_(Binds_SyncPrimCursor) {
|
||||
U4 PrimtiveArena_Used;
|
||||
U4 PrimtiveBase;
|
||||
};
|
||||
internal MipsAtom_(sync_prim_cursor) {
|
||||
/* Pop the C-struct address and base address from the tape */
|
||||
// Note(Ed): Argument shuffle....
|
||||
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimCursor,PrimtiveArena_Used)),
|
||||
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimCursor,PrimtiveBase)),
|
||||
add_ui_1( R_TapePtr, S_(Binds_SyncPrimCursor)),
|
||||
/* Calculate byte offset and store directly back to RAM */
|
||||
sub_u(R_T0, R_PrimCursor, R_T0), // R_T0 = PrimitiveArea_Used(R_AT) - R_PrimCur
|
||||
store_word(R_T0, R_AT, 0), // PrimitiveBase(R_AT)[0] = R_T0
|
||||
mac_yield()
|
||||
};
|
||||
|
||||
internal MipsAtom_(set_gte_world) {
|
||||
/* Pop matrix address from tape into R_T3 ($11) */
|
||||
load_word(R_T3, R_TapePtr, 0),
|
||||
@@ -221,7 +205,6 @@ internal MipsAtom_(set_gte_world) {
|
||||
mac_yield()
|
||||
};
|
||||
|
||||
|
||||
// TODO(Ed): I'm not sure yet if the bindings are redundant with the floortri atom yet.
|
||||
|
||||
typedef Struct_(Binds_CubeTri) {
|
||||
@@ -278,7 +261,6 @@ internal MipsAtom_(rbind_cube_tri) {
|
||||
* Inner branch (OTZ bounds): branch_equal(R_AT, R_0, 13)
|
||||
* → Skip 13 instructions from BD slot, land at add_ui(R_FaceCur,...)
|
||||
* ============================================================================ */
|
||||
atom_resource(cube_tri, "model_ship_cube")
|
||||
atom_region (cube_tri, REGION_PRIM_ARENA)
|
||||
atom_group (cube_tri, GROUP_RENDER_PRIMS)
|
||||
atom_cadence (cube_tri, CADENCE_FRAME)
|
||||
|
||||
@@ -259,7 +259,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||
tb_emit(& tb, code_cube_tri);
|
||||
}
|
||||
|
||||
tb_emit(& tb, code_sync_prim_cursor);
|
||||
tb_emit(& tb, code_sync_primitive_arena);
|
||||
tb_data(& tb, u4_(& pa->used));
|
||||
tb_data(& tb, prim_base);
|
||||
}
|
||||
@@ -351,8 +351,8 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||
for (U4 i = 0; i < Floor_num_faces; i++) {
|
||||
tb_emit(& tb, code_floor_tri);
|
||||
}
|
||||
|
||||
tb_emit(& tb, code_sync_prim_cursor);
|
||||
// After code_floor_tri iterations complete, the primitive arena's used counter is wrong.
|
||||
tb_emit(& tb, code_sync_primitive_arena);
|
||||
tb_data(& tb, u4_(& pa->used));
|
||||
tb_data(& tb, prim_base);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
atom_group( floor_tri, GROUP_RENDER_FLOOR)
|
||||
atom_cadence(floor_tri, CADENCE_FRAME)
|
||||
atom_annot( floor_tri, phase_work,
|
||||
tape_regs(R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase),
|
||||
tape_regs(R_PrimCursor, R_FaceCursor))
|
||||
atom_reads( R_PrimCursor, R_FaceCursor, R_VertBase, R_OtBase),
|
||||
atom_writes(R_PrimCursor, R_FaceCursor))
|
||||
internal
|
||||
MipsAtom_(floor_tri) {
|
||||
// T0-T2 allocated
|
||||
@@ -69,11 +69,29 @@ MipsAtom_(floor_tri) {
|
||||
|
||||
/* 8. Insert into Ordering Table Linked List */
|
||||
mac_insert_ot_tag(R_T1, 0x0400),
|
||||
add_ui(R_PrimCursor, R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
|
||||
add_ui_1(R_PrimCursor, S_(Poly_F3)), /* Advance Prim Cursor (5 words) */
|
||||
// Note(Ed): No bounds checking, should be checked before atom runs.
|
||||
|
||||
/* 9. Advance Input Cursor & Yield (Both branch targets land here) */
|
||||
atom_label(floor_tri_exit)
|
||||
add_ui(R_FaceCursor, R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
||||
add_ui_1(R_FaceCursor, S_(S2) * 4), /* Advance Face Cursor (4 * S2 = 8 bytes) */
|
||||
mac_yield()
|
||||
};
|
||||
|
||||
typedef Struct_(Binds_SyncPrimitiveArena) { U4 PrimtiveArena_Used; U4 PrimtiveBase; };
|
||||
atom_region( sync_primitive_arena, REGION_PRIM_ARENA)
|
||||
atom_group( sync_primitive_arena, GROUP_RENDER_FLOOR)
|
||||
atom_cadence(sync_primitive_arena, CADENCE_FRAME)
|
||||
atom_annot( sync_primitive_arena, phase_work,
|
||||
atom_reads( R_TapePtr, R_PrimCursor),
|
||||
atom_writes(R_TapePtr))
|
||||
internal MipsAtom_(sync_primitive_arena) {
|
||||
load_word(R_AT, R_TapePtr, O_(Binds_SyncPrimitiveArena,PrimtiveArena_Used)),
|
||||
load_word(R_T0, R_TapePtr, O_(Binds_SyncPrimitiveArena,PrimtiveBase)),
|
||||
add_ui_1( 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 - prim-base
|
||||
store_word(R_T0, R_AT, 0), // R_AT[0] = R_T0
|
||||
mac_yield()
|
||||
};
|
||||
|
||||
|
||||
@@ -265,7 +265,14 @@ local MACRO_EXPANSION = {
|
||||
["CADENCE_ONDEMAND"] = "ondemand",
|
||||
}
|
||||
|
||||
local function valid_phase(p) return KNOWN_PHASES[p] end
|
||||
-- Phases + regions + cadences are defined further below (after TAPE_ATOM_MACROS).
|
||||
-- We expose valid_phase via upvalue once KNOWN_PHASES is defined, but for now
|
||||
-- it's a closure-resolved at call time.
|
||||
|
||||
-- Table refs initialised later; valid_phase is hooked up below KNOWN_PHASES.
|
||||
local KNOWN_PHASES, KNOWN_REGIONS, KNOWN_CADENCES -- forward declarations
|
||||
|
||||
local function valid_phase(p) return KNOWN_PHASES and KNOWN_PHASES[p] or false end
|
||||
local function is_wave_context_reg(name) return WAVE_CONTEXT_REGS[name] ~= nil end
|
||||
|
||||
-- ============================================================
|
||||
@@ -315,9 +322,10 @@ end
|
||||
|
||||
-- Extract identifier args from a parenthesized group. Returns a list
|
||||
-- of {kind, value} pairs where kind is one of:
|
||||
-- "ident" -- a bare identifier (e.g. TAPE_PHASE_WORK)
|
||||
-- "regs" -- a TAPE_REGS(...) call whose args are extracted as a list
|
||||
-- "other" -- something we can't classify (preserved as text)
|
||||
-- "ident" -- a bare identifier (e.g. phase_work)
|
||||
-- "atom_reads" -- an atom_reads(...) call: value is the register list
|
||||
-- "atom_writes"-- an atom_writes(...) call: value is the register list
|
||||
-- "other" -- something we can't classify (preserved as text)
|
||||
local function parse_atom_annot_args(inner)
|
||||
-- Split at top-level commas, respecting nested parens.
|
||||
local args = {}
|
||||
@@ -325,20 +333,37 @@ local function parse_atom_annot_args(inner)
|
||||
for _, tok in ipairs(tokens) do
|
||||
local s = trim(tok)
|
||||
if s ~= "" then
|
||||
-- TAPE_REGS(...) → extract inner identifiers
|
||||
if s:sub(1, 10) == "TAPE_REGS(" and s:sub(-1) == ")" then
|
||||
local regs_inner = s:sub(11, -2)
|
||||
-- Detect register-list calls: atom_reads(...) / atom_writes(...) / tape_regs(...)
|
||||
local regs_kind = nil
|
||||
local regs_inner = nil
|
||||
if s:sub(-1) == ")" then
|
||||
if s:sub(1, 11) == "atom_reads(" then
|
||||
regs_kind = "atom_reads"
|
||||
regs_inner = s:sub(12, -2)
|
||||
elseif s:sub(1, 12) == "atom_writes(" then
|
||||
regs_kind = "atom_writes"
|
||||
regs_inner = s:sub(13, -2)
|
||||
end
|
||||
end
|
||||
|
||||
if regs_kind then
|
||||
local regs = {}
|
||||
for r in regs_inner:gmatch("[^,]+") do
|
||||
local trimmed = trim(r)
|
||||
if trimmed ~= "" then table.insert(regs, trimmed) end
|
||||
end
|
||||
table.insert(args, {kind = "regs", value = regs})
|
||||
-- Resolve any phase_* / R_* alias macros
|
||||
for i, r in ipairs(regs) do
|
||||
if MACRO_EXPANSION[r] then regs[i] = MACRO_EXPANSION[r] end
|
||||
end
|
||||
table.insert(args, {kind = regs_kind, value = regs})
|
||||
else
|
||||
-- Bare identifier (e.g. TAPE_PHASE_WORK)
|
||||
-- Bare identifier (e.g. phase_work)
|
||||
local id, _ = read_ident(s, 1)
|
||||
if id and trim(s) == id then
|
||||
table.insert(args, {kind = "ident", value = id})
|
||||
local v = id
|
||||
if MACRO_EXPANSION[v] then v = MACRO_EXPANSION[v] end
|
||||
table.insert(args, {kind = "ident", value = v})
|
||||
else
|
||||
table.insert(args, {kind = "other", value = s})
|
||||
end
|
||||
@@ -358,20 +383,20 @@ local TAPE_ATOM_MACROS = {
|
||||
}
|
||||
|
||||
-- Phase token names (must match macros in tape_atom_dsl.h)
|
||||
local KNOWN_PHASES = {
|
||||
KNOWN_PHASES = {
|
||||
["init"] = true, ["bind"] = true, ["setup"] = true,
|
||||
["work"] = true, ["commit"] = true, ["terminate"] = true,
|
||||
}
|
||||
|
||||
-- Region token names (must match REGION_* macros in tape_atom_dsl.h)
|
||||
local KNOWN_REGIONS = {
|
||||
KNOWN_REGIONS = {
|
||||
["prim_arena"] = true, ["face_arena"] = true, ["vertex_arena"] = true,
|
||||
["ot_arena"] = true, ["heap_3d_models"] = true, ["cdrom_stream"] = true,
|
||||
["vram_heap"] = true,
|
||||
}
|
||||
|
||||
-- Cadence token names (must match CADENCE_* macros in tape_atom_dsl.h)
|
||||
local KNOWN_CADENCES = {
|
||||
KNOWN_CADENCES = {
|
||||
["frame"] = true, ["once"] = true, ["ondemand"] = true,
|
||||
}
|
||||
|
||||
@@ -403,60 +428,81 @@ local function find_atom_annotations(source)
|
||||
|
||||
if #args < 1 then
|
||||
table.insert(annots, {
|
||||
line = line_of(source, i),
|
||||
line = line_of(source, i),
|
||||
macro = ident,
|
||||
kind = macro_def.kind,
|
||||
error = "missing atom name (first arg)"
|
||||
error = "missing atom name (first arg)",
|
||||
})
|
||||
else
|
||||
local name = args[1].value
|
||||
-- For TAPE_ATOM_BIND: arg layout is (name, Binds_Struct, writes)
|
||||
-- For others: (name, phase, reads, writes)
|
||||
-- INIT / TERMINATE: (name)
|
||||
-- atom_bind: (name, Binds_Struct, writes)
|
||||
-- atom_annot: (name, phase, reads, writes)
|
||||
-- atom_setup / atom_commit: (name, reads)
|
||||
-- atom_init / atom_terminate: (name)
|
||||
local entry = {
|
||||
line = line_of(source, i),
|
||||
macro = ident,
|
||||
name = name,
|
||||
kind = macro_def.kind,
|
||||
binds = nil,
|
||||
phase = nil,
|
||||
reads = {},
|
||||
writes = {},
|
||||
line = line_of(source, i),
|
||||
macro = ident,
|
||||
name = name,
|
||||
kind = macro_def.kind,
|
||||
binds = nil,
|
||||
phase = nil,
|
||||
reads = {},
|
||||
writes = {},
|
||||
errors = {},
|
||||
}
|
||||
|
||||
-- Is this arg a register-list call (any of the recognized forms)?
|
||||
local function is_regs(a)
|
||||
return a and (a.kind == "atom_reads" or a.kind == "atom_writes" or a.kind == "regs")
|
||||
end
|
||||
|
||||
if macro_def.binds then
|
||||
-- (name, Binds_Struct, writes)
|
||||
-- atom_bind(name, Binds_Struct, writes)
|
||||
if #args >= 2 and args[2].kind == "ident" then
|
||||
entry.binds = args[2].value
|
||||
end
|
||||
if #args >= 3 and args[3].kind == "regs" then
|
||||
if #args >= 3 and is_regs(args[3]) then
|
||||
-- A bind writes the wave-context, so atom_writes(...) is the
|
||||
-- canonical form, but legacy regs(...) is also accepted.
|
||||
entry.writes = args[3].value
|
||||
end
|
||||
elseif ident == "TAPE_ATOM_INIT" or ident == "TAPE_ATOM_TERMINATE" then
|
||||
-- (name) — no phase, no reads/writes to extract
|
||||
elseif ident == "TAPE_ATOM_SETUP" then
|
||||
-- (name, reads)
|
||||
if #args >= 2 and args[2].kind == "regs" then
|
||||
elseif ident == "atom_init" or ident == "atom_terminate" then
|
||||
-- (name) only, no reads/writes to extract
|
||||
elseif ident == "atom_setup" then
|
||||
-- atom_setup(name, reads)
|
||||
if #args >= 2 and is_regs(args[2]) then
|
||||
entry.reads = args[2].value
|
||||
end
|
||||
elseif ident == "TAPE_ATOM_COMMIT" then
|
||||
-- (name, reads)
|
||||
if #args >= 2 and args[2].kind == "regs" then
|
||||
elseif ident == "atom_commit" then
|
||||
-- atom_commit(name, reads)
|
||||
if #args >= 2 and is_regs(args[2]) then
|
||||
entry.reads = args[2].value
|
||||
end
|
||||
elseif ident == "TAPE_ATOM_ANNOT" then
|
||||
-- (name, phase, reads, writes)
|
||||
elseif ident == "atom_annot" then
|
||||
-- atom_annot(name, phase, reads, writes)
|
||||
if #args >= 2 and args[2].kind == "ident" then
|
||||
-- Expand TAPE_PHASE_* macro references
|
||||
local phase_id = args[2].value
|
||||
entry.phase = MACRO_EXPANSION[phase_id] or phase_id
|
||||
entry.phase = MACRO_EXPANSION[args[2].value] or args[2].value
|
||||
end
|
||||
if #args >= 3 and args[3].kind == "regs" then
|
||||
-- reads slot: atom_reads(...) is the canonical form;
|
||||
-- atom_writes(...) in the reads slot is a likely bug.
|
||||
if #args >= 3 and is_regs(args[3]) then
|
||||
if args[3].kind == "atom_writes" then
|
||||
table.insert(entry.errors,
|
||||
"reads slot has atom_writes — swap order?")
|
||||
end
|
||||
entry.reads = args[3].value
|
||||
end
|
||||
if #args >= 4 and args[4].kind == "regs" then
|
||||
-- writes slot: atom_writes(...) is canonical;
|
||||
-- atom_reads(...) here is a likely bug.
|
||||
if #args >= 4 and is_regs(args[4]) then
|
||||
if args[4].kind == "atom_reads" then
|
||||
table.insert(entry.errors,
|
||||
"writes slot has atom_reads — swap order?")
|
||||
end
|
||||
entry.writes = args[4].value
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(annots, entry)
|
||||
end
|
||||
i = after_paren
|
||||
@@ -865,11 +911,11 @@ end
|
||||
local function validate(source_path, word_counts)
|
||||
local source = read_file(source_path)
|
||||
|
||||
local annots = find_atom_annotations(source)
|
||||
local macros = find_macro_word_annotations(source)
|
||||
local pragmas = find_atom_pragmas(source)
|
||||
local binds = find_binds_structs(source)
|
||||
local atoms = find_atom_names(source)
|
||||
local annots = find_atom_annotations(source)
|
||||
local macros = find_macro_word_annotations(source)
|
||||
local pragmas = find_atom_pragmas(source)
|
||||
local binds = find_binds_structs(source)
|
||||
local atoms = find_atom_names(source)
|
||||
|
||||
-- Index for O(1) lookup
|
||||
local atom_index = {}
|
||||
@@ -892,6 +938,12 @@ local function validate(source_path, word_counts)
|
||||
msg = string.format("annotation for '%s' has no matching MipsAtom_(%s) { ... }", a.name, a.name)
|
||||
})
|
||||
end
|
||||
-- Per-entry parser errors (e.g. reads/writes slot mix-ups)
|
||||
if a.errors then
|
||||
for _, msg in ipairs(a.errors) do
|
||||
table.insert(errors, {line = a.line, msg = string.format("'%s': %s", a.name, msg)})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 2. Every atom must have exactly one annotation (no orphans, no duplicates).
|
||||
|
||||
Reference in New Issue
Block a user