From 98e27c2815c673cd5362b27bf4498f9cd5324430 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 9 Jul 2026 17:21:47 -0400 Subject: [PATCH] fixed. --- code/duffle/gen/duffle.macs.h | 6 +- code/gte_hello/gen/gte_hello.offsets.h | 14 ++--- code/gte_hello/hello_gte_tape.c | 6 +- scripts/duffle.lua | 81 +++++++++++++++++++++----- scripts/tape_atom_annotation_pass.lua | 27 +++++++-- 5 files changed, 101 insertions(+), 33 deletions(-) diff --git a/code/duffle/gen/duffle.macs.h b/code/duffle/gen/duffle.macs.h index b6a1716..d9a2286 100644 --- a/code/duffle/gen/duffle.macs.h +++ b/code/duffle/gen/duffle.macs.h @@ -2,7 +2,7 @@ #pragma once #endif // Auto-generated by tape_atom_annotation_pass.lua — DO NOT EDIT -// Source: C:/projects/Pikuma/ps1/code/duffle/lottes_tape.h +// Source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h // Component atoms (MipsAtomComp_(ac_*)) -> macro variants (mac_*) // + auto word-counts (so tape_atom.metadata.h stays manual-only // for encoding macros). @@ -60,7 +60,7 @@ WORD_COUNT(mac_load_tri_verts, 18) , 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 */ -WORD_COUNT(mac_insert_ot_tag_f3, 10) +WORD_COUNT(mac_insert_ot_tag_f3, 11) /* Words: 11; Correctly inserts a primitive into the Ordering Table linked list. * Hardcoded for Poly_G4 (9 words). For Poly_F3, use ac_insert_ot_tag_f3. */ @@ -75,7 +75,7 @@ WORD_COUNT(mac_insert_ot_tag_f3, 10) , 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 */ -WORD_COUNT(mac_insert_ot_tag_g4, 10) +WORD_COUNT(mac_insert_ot_tag_g4, 11) #define mac_pack_color_word(off, code, r, g, b) \ load_upper_i(R_AT, (code) << 8 | (b)) \ diff --git a/code/gte_hello/gen/gte_hello.offsets.h b/code/gte_hello/gen/gte_hello.offsets.h index cba333b..a20fdb0 100644 --- a/code/gte_hello/gen/gte_hello.offsets.h +++ b/code/gte_hello/gen/gte_hello.offsets.h @@ -1,24 +1,24 @@ // Auto-generated by tape_atom_offset_gen.meta.lua — DO NOT EDIT -// Source: C:/projects/Pikuma/ps1/code/gte_hello/hello_gte_tape.c +// Source: C:\projects\Pikuma\ps1\code\gte_hello\hello_gte_tape.c #pragma once #pragma region hello_gte_tape -// --- atom: cube_g4_face (50 words) --- +// --- atom: cube_g4_face (87 words) --- -#define _atom_offset_cull_cube_g4_face_exit 34 -#define _atom_offset_bounds_chk_cube_g4_face_exit 2 +#define _atom_offset_cull_cube_g4_face_exit 48 +#define _atom_offset_bounds_chk_cube_g4_face_exit 12 enum { atom_offset_cull_cube_g4_face_exit = _atom_offset_cull_cube_g4_face_exit, atom_offset_bounds_chk_cube_g4_face_exit = _atom_offset_bounds_chk_cube_g4_face_exit, }; -// --- atom: floor_f3_face (47 words) --- +// --- atom: floor_f3_face (66 words) --- -#define _atom_offset_culling_floor_f3_face_exit 14 -#define _atom_offset_bounds_chk_floor_f3_face_exit 3 +#define _atom_offset_culling_floor_f3_face_exit 29 +#define _atom_offset_bounds_chk_floor_f3_face_exit 13 enum { atom_offset_culling_floor_f3_face_exit = _atom_offset_culling_floor_f3_face_exit, diff --git a/code/gte_hello/hello_gte_tape.c b/code/gte_hello/hello_gte_tape.c index 07628b5..d517d61 100644 --- a/code/gte_hello/hello_gte_tape.c +++ b/code/gte_hello/hello_gte_tape.c @@ -9,10 +9,8 @@ #endif #pragma region MACs (Mips Atom components) -/* The macros mac_format_f3_color and mac_gte_store_f3 moved to - * lottes_tape.h during the Phase 3 gp.h overhaul. Both are now RGB-form - * (mac_format_f3_color takes _r, _g, _b byte values rather than raw - * 16-bit half-words). */ + + #pragma endregion MACs diff --git a/scripts/duffle.lua b/scripts/duffle.lua index ac91c7d..e7989bb 100644 --- a/scripts/duffle.lua +++ b/scripts/duffle.lua @@ -330,30 +330,85 @@ end -- Split a brace-body into top-level comma-separated tokens. Honors nested -- parens/braces/brackets and skips strings/comments. +-- +-- FIX (2026-07-09): split at top-level NEWLINES and SEMICOLONS too, AND +-- emit a token break after a top-level comment/string. Previous behavior +-- glued the macro call after a comment into the same token, so +-- `word_count_of_token` only saw the leading ident (often nil after +-- stripping the comment), undercounting the body. See Phase 1 of the +-- branch-offset regression investigation. Pure-comment / pure-string +-- chunks (which now appear between real statements) are filtered out so +-- they contribute 0 words instead of 1. function M.split_top_level_commas(body) local tokens = {} local i = 1 + local len = #body local token_start = 1 - while i <= #body do + + -- True iff `chunk` contains any non-whitespace, non-comment, non-string + -- content (i.e., real token material). Walks through ws + comments + -- individually so a chunk like " /* trailing */ shift_lleft(...)" + -- is correctly classified as having real content (the macro call). + local function has_real_content(chunk) + local k = 1 + local klen = #chunk + while k <= klen do + if M.is_space(chunk:sub(k, k)) then + k = k + 1 + else + local nx = M.skip_str_or_cmt(chunk, k) + if nx > k then + k = nx -- skipped a comment or string + else + return true -- found real content + end + end + end + return false + end + + local function emit(end_pos) + if end_pos >= token_start then + local chunk = body:sub(token_start, end_pos) + if M.trim(chunk) ~= "" and has_real_content(chunk) then + tokens[#tokens + 1] = chunk + end + token_start = end_pos + 1 + end + end + + while i <= len do local c = body:byte(i) - if c == 40 then local _, a = M.read_parens(body, i); i = a - elseif c == 123 then local _, a = M.read_braces(body, i); i = a - elseif c == 91 then local _, a = M.read_brackets(body, i); i = a - elseif c == 44 then -- ',' - tokens[#tokens + 1] = body:sub(token_start, i - 1) + if c == 40 then -- '(' + local _, a = M.read_parens(body, i); i = a + elseif c == 123 then -- '{' + local _, a = M.read_braces(body, i); i = a + elseif c == 91 then -- '[' + local _, a = M.read_brackets(body, i); i = a + elseif c == 44 then -- ',' + emit(i - 1) + i = i + 1 + token_start = i + elseif c == 59 then -- ';' + emit(i - 1) + i = i + 1 + token_start = i + elseif c == 10 then -- '\n' + emit(i - 1) i = i + 1 token_start = i else local nx = M.skip_str_or_cmt(body, i) - -- Don't advance token_start on skip: a trailing `/* ... */` after - -- a macro call is part of the current entry's chunk, not the - -- start of the next one. This keeps comments merged into the - -- next entry's chunk (so they don't inflate the word count). - if nx > i then i = nx else i = i + 1 end + if nx > i then + -- Skipped a comment or string at top level: emit token break. + i = nx + emit(i - 1) + else + i = i + 1 + end end end - local last = body:sub(token_start) - if M.trim(last) ~= "" then tokens[#tokens + 1] = last end + emit(len) return tokens end diff --git a/scripts/tape_atom_annotation_pass.lua b/scripts/tape_atom_annotation_pass.lua index b63e913..4ddc729 100644 --- a/scripts/tape_atom_annotation_pass.lua +++ b/scripts/tape_atom_annotation_pass.lua @@ -897,10 +897,18 @@ end -- "slot" that contributes its own word count. For most entries -- (regular MIPS instructions) the count is 1. For `mac_Y(...)` -- calls, the count is the word count of mac_Y (recursive lookup). +-- For encoding macros with a known multi-word count (e.g. +-- `mask_upper` = 2), the count is taken from `word_counts`. -- -- The component list passed in is the full set of components in the -- source, so we can resolve any `mac_X` call to its definition. -local function compute_component_word_count(c, components) +-- +-- FIX (2026-07-09): also consult `word_counts` (encoding macros from +-- tape_atom.metadata.h) for non-component tokens. Previously `mask_upper` +-- inside `mac_insert_ot_tag_*` was assumed to be 1 word instead of 2, +-- so any atom using `mac_insert_ot_tag_*` had its branch offsets off by +-- 1 word. See Phase 4b of the branch-offset regression investigation. +local function compute_component_word_count(c, components, word_counts) -- Build a lookup table: mac_X_name -> component local comp_by_name = {} for _, cc in ipairs(components) do @@ -933,8 +941,15 @@ local function compute_component_word_count(c, components) if comp_name and comp_by_name[comp_name] then -- It's a `mac_X(...)` call. Recurse. n = n + rec(comp_name) + elseif comp_name and word_counts and word_counts[comp_name] then + -- Encoding macro or pseudo-instruction (e.g. mask_upper = 2, + -- nop2 = 2). Trust the metadata — tape_atom.metadata.h is the + -- single source of truth for word counts. + n = n + word_counts[comp_name] else - -- Regular instruction (or some other token): 1 word. + -- Unrecognized token. Fall back to 1 word. tape_atom.metadata.h + -- should declare a WORD_COUNT entry for every macro used in + -- a component body — add the missing entry if you see drift. n = n + 1 end end @@ -948,7 +963,7 @@ local function compute_component_word_count(c, components) return rec(c.name) end -local function emit_component_macros_h(source_path, components) +local function emit_component_macros_h(source_path, components, word_counts) if #components == 0 then return end local dir = duffle.dirname(source_path) @@ -1024,10 +1039,10 @@ local function emit_component_macros_h(source_path, components) -- already populated) and falls back to 1 for non-mac tokens. local counts_by_name = {} for _, cc in ipairs(components) do - local cc_count = compute_component_word_count(cc, components) + local cc_count = compute_component_word_count(cc, components, word_counts) counts_by_name["mac_" .. cc.name] = cc_count end - local n = compute_component_word_count(c, components) + local n = compute_component_word_count(c, components, word_counts) if n > 0 then -- Convert `//` line comments to `/* */` block comments in each @@ -1593,7 +1608,7 @@ local function main(args) local source_text = duffle.read_file(source_path) local components = find_component_atoms(source_text) if #components > 0 then - emit_component_macros_h(source_path, components) + emit_component_macros_h(source_path, components, word_counts) end end