diff --git a/Crusader.rep/idata/00/~00000006.db/db.94.gbf b/Crusader.rep/idata/00/~00000006.db/db.100.gbf similarity index 77% rename from Crusader.rep/idata/00/~00000006.db/db.94.gbf rename to Crusader.rep/idata/00/~00000006.db/db.100.gbf index 6e76c51..4689e95 100644 Binary files a/Crusader.rep/idata/00/~00000006.db/db.94.gbf and b/Crusader.rep/idata/00/~00000006.db/db.100.gbf differ diff --git a/Crusader.rep/idata/00/~00000006.db/db.95.gbf b/Crusader.rep/idata/00/~00000006.db/db.99.gbf similarity index 77% rename from Crusader.rep/idata/00/~00000006.db/db.95.gbf rename to Crusader.rep/idata/00/~00000006.db/db.99.gbf index 010d03c..827f52d 100644 Binary files a/Crusader.rep/idata/00/~00000006.db/db.95.gbf and b/Crusader.rep/idata/00/~00000006.db/db.99.gbf differ diff --git a/Crusader.rep/user/00/~00000005.db/db.23.gbf b/Crusader.rep/user/00/~00000005.db/db.25.gbf similarity index 99% rename from Crusader.rep/user/00/~00000005.db/db.23.gbf rename to Crusader.rep/user/00/~00000005.db/db.25.gbf index decf663..de49ac6 100644 Binary files a/Crusader.rep/user/00/~00000005.db/db.23.gbf and b/Crusader.rep/user/00/~00000005.db/db.25.gbf differ diff --git a/Crusader.rep/user/00/~00000005.db/db.24.gbf b/Crusader.rep/user/00/~00000005.db/db.26.gbf similarity index 99% rename from Crusader.rep/user/00/~00000005.db/db.24.gbf rename to Crusader.rep/user/00/~00000005.db/db.26.gbf index dd92028..085e9d9 100644 Binary files a/Crusader.rep/user/00/~00000005.db/db.24.gbf and b/Crusader.rep/user/00/~00000005.db/db.26.gbf differ diff --git a/crusader_decompilation_notes.md b/crusader_decompilation_notes.md index 3bc835c..edf9a68 100644 --- a/crusader_decompilation_notes.md +++ b/crusader_decompilation_notes.md @@ -1878,18 +1878,18 @@ Current structural read of the cache globals: - Reuses the incoming FAR pointer when non-null; otherwise allocates `0x33` bytes through `mem_alloc_far`. - Initializes the entry through `entity_dispatch_entry_init`. - Stamps the entry type word at `+0x00` to `0x0f5e` before returning it. -- `0009:b1c3` remains conservatively unnamed, but it is now annotated as a phase-selected finalize helper: +- `0009:b1c3` is now renamed `allocator_phase_finalize_pass` and remains intentionally allocator-scoped rather than subsystem-specific: - Both known call sites pass only phase bytes `0` or `1`. - It forwards that byte twice to the object rooted at `0x4588` through vtable slot `+0x08`. - - It then sweeps the table rooted at `0x8724` up to count `0x879c`, calling `FUN_0009_a961` on each entry. -- That evidence is strong enough for comments, but not yet enough to promote `0009:b1c3` or `0x4588` to a more specific subsystem name. + - It then sweeps the allocator head table at `0x8724` up to the active head count at `0x879c`, calling `allocator_head_finalize_sweep` on each entry. +- That evidence is strong enough for the allocator-side rename, but not yet enough to promote `0x4588` to a more specific subsystem name. ### Follow-up: seg082 allocator cluster (`0009:a229`, `0009:af87`, `0009:b06b`, `0009:b1c3`) - `0009:a229` is now verified as the public size-only wrapper around the seg082 allocator path. - Caller evidence: - `saveslot_table_clear` requests `0x2800` bytes through `0009:a229`, stores the returned FAR pointer at `0x2ba3/0x2ba5`, then zeroes the result in `0x400`-byte chunks. - - The wrapper lazily initializes the allocator on first use through `0009:bcb9`, then calls `0009:b06b(size, default_tag, 0xff)`. + - The wrapper lazily initializes the allocator on first use through `0009:bcb9`, then calls `allocator_try_alloc_from_head_table(size, default_tag, 0xff)`. - `0009:bcb9` is now annotated as the one-time lazy initializer for this path. - It parses an optional `-x` tuning value from the PSP command line, clamps the derived percentage into `0x14..0x50`, then seeds local seg082 helpers before setting init flag `0x4096 = 1`. - Table structure around `0x8724` is tighter now: @@ -1900,24 +1900,24 @@ Current structural read of the cache globals: - It walks the node chain rooted at `0x8724`. - For each node, it accumulates `node_size - 9` into a running total and tracks the largest single free block. - Known callers include `cache_init` and the seg013 path at `0004:833b`, both of which use it to size subsequent allocation work. -- `0009:b06b` has been traced further as the internal sweep allocator for this cluster. - - It validates the requested size, reserves a temporary work token through `0009:e15f`, and scans the `0x8724` table in `0x0c`-byte entries via the local helper at `0009:a336`. +- `0009:b06b` is now renamed `allocator_try_alloc_from_head_table`. + - It validates the requested size, reserves a temporary work token through `0009:e15f`, and scans the `0x8724` allocator head table in `0x0c`-byte entries via the local helper at `0009:a336`. - On a successful fit, it commits the result through `0009:e2b4`, clears failure flag `0x4098`, and returns the allocated FAR pointer. - - When a pass does not find a fit, it interleaves up to two finalize phases through `0009:b1c3(phase)` before the final retry, then releases the work token through `0009:e1f6`. + - When a pass does not find a fit, it interleaves up to two finalize phases through `allocator_phase_finalize_pass(phase)` before the final retry, then releases the work token through `0009:e1f6`. - The formerly missing callee at `0009:a336` has now been recovered in-place as `allocator_head_try_alloc_block` with body `0009:a336-0009:a5d0`. - - It is the per-head first-fit allocator helper used by `0009:b06b` while sweeping the `0x8724` head table. + - It is the per-head first-fit allocator helper used by `allocator_try_alloc_from_head_table` while sweeping the `0x8724` allocator head table. - It normalizes the requested size (rounds odd small requests up, page-aligns large non-page-aligned requests), adds the local `0x0a` node header overhead, and enforces a minimum allocation size of `0x10` bytes. - It walks the node chain for one allocator head until it finds a free span large enough. - On success it unlinks the chosen free node, either consumes it whole or splits off a remainder node when at least `0x10` bytes remain, stores the owner/tag word, and returns `payload_ptr + 0x0a`. - - On failure for that head it returns `0`, which matches the calling pattern in `0009:b06b`. + - On failure for that head it returns `0`, which matches the calling pattern in `allocator_try_alloc_from_head_table`. - Boundary follow-up from the same read-only scan: - The adjacent missing body at `0009:a5d1` has now also been recovered in-place as `allocator_head_free_block` with body `0009:a5d1-0009:a960`. - It is the per-head free helper paired with `allocator_head_try_alloc_block`. - It rebuilds the node header from a payload pointer (`payload - 0x0a`), validates the owner/tag word against the expected caller-supplied tag, reinserts the block into one allocator head, and coalesces with adjacent free neighbors when possible. - Its earlier branch targets `0009:a7a1` and `0009:a7b8` are now confirmed to be internal labels, not separate function entries. -- `0009:a961` is now better constrained as the per-head finalize sweep used by `0009:b1c3`. +- `0009:a961` is now better constrained as the per-head finalize sweep used by `allocator_phase_finalize_pass`. - It walks one `0x8724` head's node chain, skips odd-tagged spans, coalesces or rewrites eligible spans, and updates head/back-pointer links when deferred space needs to be merged back into the chain. - - This strengthens the current interpretation that `0009:b1c3` is a phase-selected allocator-finalize pass rather than a cache-specific public API. + - This strengthens the current interpretation that `allocator_phase_finalize_pass` is allocator-side callback/finalize glue rather than a cache-specific public API. - `0009:b224` is now named `allocator_free_block_by_ptr`. - Current verified behavior: converts the payload pointer back through the local header helpers, scans the `0x8724` head table for the owning range, dispatches to `allocator_head_free_block`, and aborts if no owning head is found. - Known wrappers `0009:a24f` and `0009:a27a` are now clearly small checked entry points into this free-by-pointer path. @@ -1925,8 +1925,8 @@ Current structural read of the cache globals: - `allocator_head_try_alloc_block` (`0009:a336`) - `allocator_head_free_block` (`0009:a5d1`) - `allocator_free_block_by_ptr` (`0009:b224`) -- `0009:b1c3` now has a corrected single-byte phase parameter in Ghidra; the object at `0x4588` is still left unnamed because its subsystem role is not yet strong enough. -- This narrows the remaining ambiguity around `0009:b1c3`: the unresolved part is now the role of the object at `0x4588`, not the local allocator mechanics around `0x8724`. `ASYLUM.24` is still not identified from the current evidence. +- `allocator_phase_finalize_pass` now has a corrected single-byte phase parameter in Ghidra; the object at `0x4588` is still left unnamed because its subsystem role is not yet strong enough. +- This narrows the remaining ambiguity around `allocator_phase_finalize_pass`: the unresolved part is now the role of the object at `0x4588`, not the local allocator mechanics around `0x8724`. `ASYLUM.24` is still not identified from the current evidence. ### Follow-up: `0x4588` object-role evidence (Priority 1 start) @@ -1934,6 +1934,7 @@ Current structural read of the cache globals: - Current verified behavior from those uses: - `entity_conditional_render_dispatch` (`0009:9216`) calls through the runtime-installed object at `0x4588` via vtable slot `+0x0c` when the entity flags allow the alternate path and `param_2 == 0`. - `000a:4a56` is a one-shot teardown/reset path for the same object: it checks a local once-flag at `0x4595`, clears `0x4588` when non-null, optionally performs a vtable `+0x0c` callback when `0x4590 != 0x458c`, then calls vtable slot `+0x04` followed by `FUN_0009_0d30()`. + - The two callback sync sites inside `sprite_node_get_or_traverse` (`000a:b9e5` and `000a:ba66`) only emit vtable `+0x0c` when the candidate two-word pair differs from the current pair, then immediately mirror that pair through `000b:1e39` using global sprite/object pointer `0x4f38/0x4f3a`. - A read-only data probe of `0x4588` in the current database returned all zero bytes, so the object pointer is null-initialized statically and likely installed later at runtime. - Conservative conclusion: - The `0x4588` object now looks like a runtime-installed callback / dispatch object that participates in conditional render or presentation-side flow and has an explicit teardown path. @@ -1953,6 +1954,88 @@ Current structural read of the cache globals: - The unresolved part is now its concrete subsystem identity, not whether the object lifecycle is real. - The best next cheap win is no longer broad instruction searching; it is caller-side recovery around the still-unbounded `000a:b9e5` / `000a:ba66` and `000d:9d5e` / `000d:a3b7` windows. +### Follow-up: seg138 caller-side dispatch-entry emission helper + +- `FUN_000d_938c` is now confirmed as a real caller-side helper with body `000d:938c-000d:9583`, and an evidence-preserving decompiler comment was added in Ghidra instead of forcing a speculative rename. +- Current verified behavior from direct MCP decompile/disassembly: + - When the mode/global gate is not already in the `0x13:0x0008` state and entity byte `+0x33` is clear, it allocates a scratch palette buffer, constructs a dispatch entry, sets type `0x051e`, and initializes runtime state through `entity_dispatch_entry_init_runtime_state` with entry kind `0x3c`. + - Later in the same helper it constructs a second dispatch entry from the current palette globals at `0x4e4:0x4e6`, again sets type `0x051e`, and initializes runtime state with entry kind `0x14` and active-state parameters `(1,0,1)`. + - Both created entries are polled until their runtime flag word clears bit `0x0002`, after which the helper redraws the global sprite path, syncs display-state byte `0x58e` from the entity when the global display object exists, calls `FUN_0006_16e1`, clears `g_active_dispatch_entry_farptr[+0x40]`, and finally dispatches through the input object's vtable slot `+0x08`. +- Conservative conclusion: + - seg138 now has one more verified caller tying `entity_dispatch_entry_init_runtime_state` to palette/presentation-side emission work around entity cleanup and redraw flow. + - This narrows the open question from "is the dispatch-entry lane real?" to "what exact presentation/event subsystem does this lane belong to?" + +### Follow-up: seg137 palette and dispatch-entry helper family + +- A larger direct MCP rename batch now stabilizes a coherent seg137 palette helper family: + - `000d:82ea` = `dispatch_entry_create_black_palette_state_active` + - `000d:83be` = `dispatch_entry_create_grayscale_palette_state_active` + - `000d:85da` = `vga_palette_set_all_black` + - `000d:8653` = `vga_palette_set_all_white` + - `000d:86cc` = `vga_palette_set_all_rgb` + - `000d:875d` = `dispatch_entry_create_solid_palette_state_active` + - `000d:88b2` = `dispatch_entry_create_solid_palette_state` + - `000d:8a47` = `dispatch_entry_create_black_palette_state` +- Current verified behavior from direct MCP decompile/disassembly: + - `vga_palette_set_all_black` corrects the earlier overreach rename at `000d:85da`: it allocates a `0x100`-entry palette buffer filled with zero RGB triplets, writes it to VGA, and frees the scratch buffer. The previous `map_object_set_dirty_flag` name was not supported by the recovered body. + - `vga_palette_set_all_white` is the same helper shape with all three RGB components initialized to `0x3f`, then written through `vga_palette_write`. + - `vga_palette_set_all_rgb` takes caller-supplied RGB bytes, replicates them across a `0x100`-entry palette buffer, writes the result to VGA, and frees the scratch palette. + - `dispatch_entry_create_black_palette_state_active` and `dispatch_entry_create_black_palette_state` both build a runtime-state dispatch entry of type `0x051e` from a black `0x100`-entry palette buffer; the `_active` form first sets `g_active_dispatch_entry_farptr[+0x40] = 1`, while the quiet form does not. + - `dispatch_entry_create_grayscale_palette_state_active` reads the current VGA palette, normalizes each triplet by copying the first channel across all three RGB bytes, then builds a runtime-state dispatch entry from that grayscale palette while marking the active dispatch entry. + - `dispatch_entry_create_solid_palette_state_active` and `dispatch_entry_create_solid_palette_state` validate `0..0x3f` RGB inputs, fill a scratch `0x100`-entry palette buffer with that solid color, and build the same `0x051e` runtime-state dispatch entry, again split into active-marking and quiet variants. +- Additional caller-side comments were added instead of speculative renames on: + - `000d:84f4` (current-palette dispatch entry paired with a second object of type `0x68bf` through `entity_pair_sync_b`) + - `000d:89c6` (parameterized current-palette runtime-state wrapper with active-state flags) +- Conservative conclusion: + - seg137 is now materially beyond a foothold: it contains a coherent palette-write and palette-backed dispatch-entry emission family tied to the same runtime-state constructor lane. + - The remaining uncertainty is higher-level script/event meaning, especially the paired `0x68bf` object and the exact role of the `0004:5ad4-5b6e` caller sequence, not the local palette-helper mechanics. + +### Follow-up: seg005 startup/display orchestration and seg136 active dispatch entry + +- A new direct MCP recovery pass stabilized one high-value handoff path and its nearby active-dispatch helpers: + - `0004:60c0-0004:621a` recovered as `FUN_0004_60c0` with a decompiler comment summarizing the orchestration flow. + - `000d:7600-000d:760d` created and renamed to `active_dispatch_entry_mark_enabled`. + - `000d:760e` renamed to `active_dispatch_entry_mark_disabled`. + - `000d:761c` renamed to `active_dispatch_entry_create_default`. +- Current verified behavior from direct MCP decompile/disassembly: + - `FUN_0004_60c0` is a recovered startup/display orchestration path: it performs broad setup calls, reads the live VGA palette, validates a caller-provided object through vtable slot `+0x0c`, drives the sprite/object lane through `0x4f38`, runs the seg137 palette and dispatch-entry helper family, creates the default active dispatch entry through `active_dispatch_entry_create_default`, programs mouse interrupt state via seg056 `INT 33h` wrappers, then hands off into the still-unrecovered `0004:1e00` routine. + - The old `0004:5ad4-5b6e` caller sequence is now confirmed as one internal sub-sequence within that larger recovered function rather than an isolated orphan. + - `active_dispatch_entry_create_default` allocates or reuses a `0x42`-byte dispatch entry, stamps type `0x687f`, installs a callback-table pointer through `0x39ca`, sets event type `0x248`, sets update period `0x1e`, marks the entry as the global active dispatch entry at `0x6828`, toggles the local `+0x40` state byte through `active_dispatch_entry_mark_enabled` and `active_dispatch_entry_mark_disabled`, then enables the timer wrapper. + - `active_dispatch_entry_mark_enabled` and `active_dispatch_entry_mark_disabled` are tiny helpers that set or clear `g_active_dispatch_entry_farptr[+0x40]` respectively. +- Conservative conclusion: + - seg005 now has its first strong high-value foothold in a startup/display handoff path, even though the downstream `0004:1e00` target still needs recovery and naming. + - seg136 now has a concrete active-dispatch-entry foothold rather than being empty ledger space. + +### Follow-up: seg005 large runtime/display handoff body recovered at `0004:1e00` + +- `0004:1e00-0004:2420` has now been recovered as a real function object in Ghidra as `FUN_0004_1e00` with an evidence-preserving comment, replacing the earlier no-function gap. +- Current verified behavior from the recovered body: + - It begins by forcing an all-black palette through `vga_palette_set_all_black`, then performs several startup/display setup calls before manipulating the active dispatch entry at `0x6828`. + - It constructs two animation-side objects through `animation_ctor_variant_b` (`000e:2860`) using DS-local descriptors at `0x04ae` and `0x04b2`, then waits on global words around `0x8a94-0x8a98` when the alternate startup flag path is active. + - It conditionally calls `sprite_node_get_or_traverse` (`000a:b988`) after a seg122 helper path, toggles seg064 gate helpers, and then enters a larger resource/object processing region that uses globals rooted at `0x4aa`, `0x4ac`, and `0x7e22`. + - The mid-body is now better classified as a non-return transition driver rather than a generic handoff stub: it branches on the returned `SI` state after the sprite/object traversal, with one path performing the fuller runtime/display setup, one path taking a small local special-case handler (`0004:2661`), and one path marking the active dispatch entry before calling `runtime_callback_object_teardown_once(1)`. + - The `SI == 2` special-case branch is now slightly tighter: its local helper `0004:2661` forwards into `FUN_0004_25df`, which is a small type-stamped dispatch-entry constructor that allocates when needed, runs `entity_dispatch_entry_init`, stamps type `0x04b6`, and stores the caller-supplied mode/state word at `+0x32`. + - The fuller setup path clears and restores active-dispatch state, calls through the `0x2bd8` object vtable, restores the live palette through `0009:6f5a`, re-runs render/dispatch rectangle helpers (`entity_conditional_render_dispatch`, `entity_rect_compare_and_dispatch`), and finishes through the seg126 trampoline `thunk_callf_0000_ffff_000c_82f9`. + - The recovered tail confirms a clean end at `0004:2420`, with the next separate function beginning at `0004:2421`. +- Conservative conclusion: + - The main blocker on seg005 is no longer structural recovery; it is naming the exact state entered by this now-navigable startup/display transition driver. + - The presence of `animation_ctor_variant_b`, palette forcing, active-dispatch toggles, sprite-node traversal, and the `0x2bd8` vtable lane makes this look more like a real mode/state transition than a one-off helper, but the exact gameplay, intro, or front-end label still needs one more caller/data pass. + +### Follow-up: seg126 wrappers feeding the `0004:1e00` transition lane + +- Two previously unbounded seg126 callers around the recovered seg005 handoff are now real functions in Ghidra: + - `FUN_000c_7412` (`000c:7412-000c:7432`) + - `FUN_000c_c9f4` (`000c:c9f4-000c:ca1c`) +- The larger fallthrough body rooted at `000c:c890` is now also recovered as a real function object: `FUN_000c_c890` (`000c:c890-000c:c9f3`). +- Current verified behavior from direct MCP recovery/decompile: + - `FUN_000c_7412` is a compact wrapper into the seg005 transition lane: it clears the redraw state on the sprite/object pair rooted at `0x5e82:0x5e84`, forces a black palette through `vga_palette_set_all_black`, runs seg126 pre-entry state prep through `FUN_000c_c9f4`, then tail-calls `FUN_0004_1e00`. + - `FUN_000c_c9f4` is a short pre-entry state wrapper: it runs local seg126 setup helpers, repeatedly executes a local prep loop while state byte `0x62fe` is clear and fallback word `0x31a2` is zero, then dispatches into local helper `000c:c890` before returning to callers that continue into `FUN_0004_1e00`. + - `FUN_000c_c890` is the main seg126 pre-entry preparation body behind that wrapper: it releases up to two tracked object pairs at `0x8c5c` and `0x8c60`, conditionally frees the local pair at `0x6301:0x6303`, runs palette/render reset, conditionally constructs animation state through `animation_ctor_variant_a` on `DS:0x6341` when `0x844` and `0x62fe` are both set, marks the active dispatch entry, primes sprite redraw state, drains the event queue, and zeroes `0x8a94-0x8a98` before returning. + - This is now enough to tie the seg076 caller at `000c:742c` to the same startup/display transition lane already reached from `FUN_0004_60c0`. +- Conservative conclusion: + - seg126 now has a real foothold in the startup/runtime entry path rather than only isolated thunks and trampolines. + - The unresolved part is the exact meaning of the local state bytes and object lanes around `0x62fe`, `0x31a2`, `0x8c5c`, `0x8c60`, and `DS:0x6341`, not whether the wrapper lane itself is real. + ### Follow-up: `ASYLUM.24` vs nearby `ASYLUM` ordinals - `ASYLUM.24` remains unresolved by name, but its call pattern is now narrower. diff --git a/crusader_segment_coverage_ledger.csv b/crusader_segment_coverage_ledger.csv index c946a27..b8e34ec 100644 --- a/crusader_segment_coverage_ledger.csv +++ b/crusader_segment_coverage_ledger.csv @@ -3,7 +3,7 @@ "2","code","0x40000","0x2B0","None","","","","crusader_ne_segments.csv" "3","code","0x40400","0x55A","None","","","","crusader_ne_segments.csv" "4","code","0x40A00","0x10B1","Foothold","Reset/cache entry path","runtime_cache_reset_sequence","ASYLUM.24 and downstream reset callers still need tighter classification","crusader_decompilation_notes.md; plan-mid.md" -"5","code","0x41E00","0x8D7","None","","","","crusader_ne_segments.csv" +"5","code","0x41E00","0x8D7","Foothold","Startup/display orchestration and large runtime handoff","FUN_0004_60c0; FUN_0004_1e00","Recovered bodies now exist, but exact subsystem naming and higher-level transition meaning remain open","crusader_decompilation_notes.md; plan-mid.md" "6","code","0x42C00","0x75E","None","","","","crusader_ne_segments.csv" "7","code","0x43600","0x484","None","","","","crusader_ne_segments.csv" "8","code","0x43C00","0x1386","None","","","","crusader_ne_segments.csv" @@ -80,7 +80,7 @@ "79","code","0x98600","0x421","None","","","","crusader_ne_segments.csv" "80","code","0x98C00","0xF27","Foothold","Conditional render/callback dispatch and surface release","entity_conditional_render_dispatch; surface_release_internal; surface_release_and_maybe_free","0x4588 callback object still lacks a concrete subsystem name","crusader_decompilation_notes.md" "81","code","0x99E00","0x320","None","","","","crusader_ne_segments.csv" -"82","code","0x9A200","0x1C8A","Partial","Allocator sweep and per-head allocation/finalize","allocator_head_try_alloc_block; allocator_head_free_block; allocator_head_finalize_sweep; public size wrapper","0x4588 object subsystem identity still unresolved","crusader_decompilation_notes.md; plan-mid.md" +"82","code","0x9A200","0x1C8A","Partial","Allocator head-table allocation and phase finalize","allocator_try_alloc_from_head_table; allocator_phase_finalize_pass; allocator_head_try_alloc_block; allocator_head_free_block; allocator_head_finalize_sweep","0x4588 callback object subsystem identity still unresolved","crusader_decompilation_notes.md; plan-mid.md" "83","code","0x9C400","0x31E","Foothold","Allocator node/header helpers","event_queue_push; packed size/header helpers","Mostly structural helper layer","crusader_decompilation_notes.md" "84","code","0x9C800","0x1478","None","","","","crusader_ne_segments.csv" "85","code","0x9E000","0x404","Foothold","Allocator work token helpers","token reserve/release and commit helpers","Needs clearer subsystem naming","crusader_decompilation_notes.md" @@ -124,7 +124,7 @@ "123","code","0xC3C00","0xE6D","None","","","","crusader_ne_segments.csv" "124","code","0xC4E00","0x3DD","None","","","","crusader_ne_segments.csv" "125","code","0xC5400","0x1A3E","None","","","","crusader_ne_segments.csv" -"126","code","0xC7400","0x402A","None","","","","crusader_ne_segments.csv" +"126","code","0xC7400","0x402A","Foothold","Runtime-entry wrappers and pre-entry state prep","FUN_000c_7412; FUN_000c_c890; FUN_000c_c9f4; thunk_callf_0000_ffff_000c_827d","Broader seg126 state-machine/helper meanings remain open, but this lane now clearly feeds the seg005 startup/display transition","crusader_decompilation_notes.md; plan-mid.md" "127","code","0xCC600","0x8F6","None","","","","crusader_ne_segments.csv" "128","code","0xCD200","0x5D0","None","","","","crusader_ne_segments.csv" "129","code","0xCDA00","0xD77","None","","","","crusader_ne_segments.csv" @@ -134,9 +134,9 @@ "133","code","0xD3800","0x215A","None","","","","crusader_ne_segments.csv" "134","code","0xD6000","0xEF0","None","","","","crusader_ne_segments.csv" "135","code","0xD7000","0x3B7","None","","","","crusader_ne_segments.csv" -"136","code","0xD7600","0x5BD","None","","","","crusader_ne_segments.csv" -"137","code","0xD7E00","0xFBB","Foothold","Dispatch-entry runtime state init/release","entity_dispatch_entry_init_runtime_state; entity_dispatch_entry_release_runtime_state","Higher-level callback object role and event semantic naming still unresolved","crusader_decompilation_notes.md; plan-mid.md" -"138","code","0xD9200","0x32E4","Foothold","Entity cleanup/finalize with callback and palette/file teardown","entity_cleanup_resources_and_dispatch; sprite_redraw_global_if_active","Callback-object role naming and 000d:7e00 constructor/dispatch path are still unresolved","crusader_decompilation_notes.md; plan-mid.md" +"136","code","0xD7600","0x5BD","Foothold","Active dispatch-entry lifecycle helpers","active_dispatch_entry_mark_enabled; active_dispatch_entry_mark_disabled; active_dispatch_entry_create_default","Broader meaning of the active dispatch entry and its relationship to the startup/display lane still needs caller-side confirmation","crusader_decompilation_notes.md; plan-mid.md" +"137","code","0xD7E00","0xFBB","Partial","Palette and dispatch-entry emission helper family","entity_dispatch_entry_init_runtime_state; entity_dispatch_entry_release_runtime_state; vga_palette_set_all_black; vga_palette_set_all_white; vga_palette_set_all_rgb; dispatch_entry_create_black_palette_state_active; dispatch_entry_create_grayscale_palette_state_active; dispatch_entry_create_solid_palette_state_active","Higher-level event/script meaning is still unresolved, especially the paired 0x68bf object and the exact role of the 0004:5ad4-5b6e caller sequence","crusader_decompilation_notes.md; plan-mid.md" +"138","code","0xD9200","0x32E4","Foothold","Entity cleanup/finalize with callback and dispatch-entry palette emission","entity_cleanup_resources_and_dispatch; sprite_redraw_global_if_active","Concrete callback-object subsystem naming is still unresolved; FUN_000d_938c is now verified as a caller-side dispatch-entry/palette emission helper but remains intentionally unnamed","crusader_decompilation_notes.md; plan-mid.md" "139","code","0xDCC00","0x984","None","","","","crusader_ne_segments.csv" "140","code","0xDD800","0xC6F","None","","","","crusader_ne_segments.csv" "141","code","0xDE600","0x2B","None","","","Short stub-sized segment","crusader_ne_segments.csv" diff --git a/plan-mid.md b/plan-mid.md index b899aa9..d2bddb6 100644 --- a/plan-mid.md +++ b/plan-mid.md @@ -20,30 +20,36 @@ The estimates below are intentionally conservative. They measure verified behavi - Priority 0 has started: `crusader_segment_coverage_ledger.csv` exists and contains a first-pass 145-row ledger. - The currently seeded ledger rows are conservative and strongest around seg001, seg004, seg021, seg043, seg080, seg082/083/085, seg091, seg094, and seg095. -- Priority 1 has started on the cache/backend cluster: the seg082 allocator mechanics are now materially recovered (`allocator_head_try_alloc_block`, `allocator_head_free_block`, `allocator_free_block_by_ptr`), and the `0x4588` path now has named lifecycle helpers (`runtime_callback_object_init_once`, `runtime_callback_object_teardown_once`, `runtime_callback_object_phase_finalize`). +- Priority 1 has started on the cache/backend cluster: the seg082 allocator mechanics are now materially recovered (`allocator_head_try_alloc_block`, `allocator_head_free_block`, `allocator_free_block_by_ptr`, `allocator_try_alloc_from_head_table`, `allocator_phase_finalize_pass`), and the `0x4588` path now has named lifecycle helpers (`runtime_callback_object_init_once`, `runtime_callback_object_teardown_once`). - The `0x4588` blocker is tighter than before: `000a:b988` boundary repair now includes both callback sync callsites (`000a:b9e5` / `000a:ba66`) inside one real function body, `000d:9d5e` / `000d:a3b7` are confirmed inside `entity_cleanup_resources_and_dispatch`, and adjacent helpers are now clarified as `allocator_head_finalize_sweep` (`0009:a961`), `video_bios_state_snapshot` (`000a:4a1f`), and `video_mode_set_and_record_state` (`000a:4972`). Concrete subsystem identity is still unresolved. - A larger MCP rename batch completed for cleanup callees: `palette_buffer_alloc_and_init_256` (`0009:7853`), `file_handle_alloc_init_and_open` (`0009:1c3a`), `file_handle_open_with_mode` (`0009:1d6a`), `surface_release_internal` (`0009:8d7b`), `surface_release_and_maybe_free` (`0009:8e0a`), and `sprite_redraw_global_if_active` (`000d:9231`). This reduces `entity_cleanup_resources_and_dispatch` ambiguity on file/surface/palette teardown paths. - The previously missing `000d:7e00` function object is now recovered and named `entity_dispatch_entry_init_runtime_state`, with paired destructor `entity_dispatch_entry_release_runtime_state` at `000d:8078`. Adjacent missing helpers `0003:a880` and `0003:b8e2` were also recovered, with `0003:b8e2` promoted to `far_buffer_alloc_with_mode_flags`. - Additional helper stabilization now covers seg061/064/076: `vga_palette_read` (`0009:6ec7`) is confirmed alongside existing palette write/free paths, `timer_entity_enable_wrapper` (`0008:d3ba`) is named, and seg064 one-shot gate helpers around `0x3b72/0x3b73` are documented with conservative comments while keeping speculative naming deferred. - Constructor-lane semantics tightened further: `entity_set_update_period_and_reschedule` (`0008:d27e`) and `palette_buffer_alloc_copy_from_source` (`0009:7905`) are now named, and both `0x4588` callback emit callsites (`000d:9d5e`, `000d:a3b7`) now have explicit payload-pair annotations in disassembly. +- The seg082 allocator table structure is now pinned down as the allocator head table at `0x8724` and active head count at `0x879c`, and the old structural helpers at `0009:b06b` / `0009:b1c3` are now promoted to `allocator_try_alloc_from_head_table` and `allocator_phase_finalize_pass`. +- New caller-side seg138 evidence now exists at `FUN_000d_938c` (`000d:938c-000d:9583`): it builds one scratch-palette dispatch entry (`kind 0x3c`) and one current-palette dispatch entry (`kind 0x14`) through `entity_dispatch_entry_init_runtime_state`, waits for each entry's active flag to clear, then redraws the global sprite path and dispatches through the input object's vtable slot `+0x08`. This narrows the open lane to presentation/dispatch semantics without yet justifying a concrete subsystem rename. +- seg137 is now promoted from `Foothold` to `Partial`: direct MCP recovery stabilized a coherent palette/dispatch-entry helper family with safe renames for all-black, all-white, arbitrary-RGB, grayscale, black-state, and solid-color state builders around the same `entity_dispatch_entry_init_runtime_state` lane. The remaining gap is the higher-level event/script meaning of those helpers, not the local mechanics. +- seg005 and seg136 now have new high-value footholds: `FUN_0004_60c0` is recovered as a startup/display orchestration handoff that drives the seg137 palette helper family, validates an object through vtable `+0x0c`, creates the default active dispatch entry, programs mouse state, and then hands off into `0004:1e00`; nearby seg136 helpers are now stabilized as `active_dispatch_entry_mark_enabled`, `active_dispatch_entry_mark_disabled`, and `active_dispatch_entry_create_default`. +- The downstream seg005 handoff body is now also classified further: `FUN_0004_1e00` (`0004:1e00-0004:2420`) is a non-return startup/display transition driver with confirmed use of `vga_palette_set_all_black`, `animation_ctor_variant_b`, `sprite_node_get_or_traverse`, seg064 gate helpers, the `0x2bd8` vtable lane, and the `0x4aa/0x7e22` resource/object lane. The remaining work is naming the exact state label, not repairing the structure. +- seg126 now has a deeper foothold instead of only wrapper coverage: `FUN_000c_7412`, `FUN_000c_c9f4`, and the newly recovered `FUN_000c_c890` now show a coherent pre-entry preparation lane that releases tracked objects, resets palette/render state, conditionally constructs animation state at `DS:0x6341`, and then feeds the same `FUN_0004_1e00` startup/display transition from the seg076 side. ### Current Focus 1. Finish Priority 0 refinement by promoting more exact segment rows where notes already support a verified foothold. -2. Continue the Priority 1 pass by tracing remaining caller-side `0x4588` / `0009:b1c3` object-role evidence now that the `000d:7e00` constructor/destructor path is readable. +2. Continue the Priority 1 pass by tracing the higher-level startup/display callers, branch outcomes, and pre-entry object lanes that stitch the seg137 palette helper family into the wider `0x4588` / dispatch-entry object-role lane. ### Next Resume Point -1. Update the ledger for any additional exact segment anchors found in the reset/cache or render-path notes. -2. Continue caller-role classification inside `entity_cleanup_resources_and_dispatch` (contains both `000d:9d5e` and `000d:a3b7`) and map how it relates to `runtime_callback_object_phase_finalize` + `allocator_head_finalize_sweep`. -3. Promote additional field-level names inside `entity_cleanup_resources_and_dispatch` and `entity_dispatch_entry_init_runtime_state` now that update-period/palette-copy helpers are named. -4. Classify remaining callback-role semantics for the `0x4588` object (especially vtable `+0x08` vs `+0x0c` intent and phase/event meaning) using the confirmed payload pairs `+0x12d/+0x12f` and `+0x74f/+0x751`. -5. Continue `ASYLUM.24` only after the `0x4588` path has no further cheap wins. +1. Classify the remaining seg126 pre-entry object lanes around `FUN_000c_c890`, especially tracked pairs `0x8c5c`, `0x8c60`, local state gates `0x62fe` / `0x31a2`, and animation buffer/object `DS:0x6341`. +2. Continue caller-role classification inside `entity_cleanup_resources_and_dispatch` (contains both `000d:9d5e` and `000d:a3b7`) and map how it relates to `FUN_000d_938c`, `FUN_0004_60c0`, `FUN_000c_7412`, `FUN_000c_c890`, and the seg136/seg137 active-dispatch helper family. +3. Clarify the object validated through `FUN_0004_60c0` vtable slot `+0x0c` and how it relates to the sprite/object lane at `0x4f38`, the `0x2bd8` vtable callbacks used inside `FUN_0004_1e00`, and the tracked object pairs released by `FUN_000c_c890`. +4. Revisit `allocator_phase_finalize_pass` only where it intersects the same callback object semantics, rather than broad allocator mechanics that are already sufficiently constrained. +5. Continue `ASYLUM.24` only after the `0x4588` / dispatch-entry lane and `0004:1e00` transition path have no further cheap wins. ### Headline Estimate -- Overall useful decompilation progress: about 25% -- Reasonable uncertainty band: about 20% to 30% +- Overall useful decompilation progress: about 30% +- Reasonable uncertainty band: about 25% to 35% This is the best single-number estimate for the full game right now. @@ -52,8 +58,8 @@ This is the best single-number estimate for the full game right now. | Metric | Estimate | Meaning | |---|---:|---| | Top 100 far-call target coverage | about 80% | Roughly 80 of the top 100 most-called far-call targets have been named or materially classified | -| Whole-program behavioral coverage | about 25% | Verified subsystem and function understanding across the executable | -| Segment spread with meaningful analysis | about 10% to 15% | Segments with more than a trivial foothold or isolated note | +| Whole-program behavioral coverage | about 30% | Verified subsystem and function understanding across the executable | +| Segment spread with meaningful analysis | about 14% to 20% | Segments with more than a trivial foothold or isolated note | | Tooling maturity for continued work | about 75% | Core repair, lookup, and fallback automation needed for continued progress | ### Why These Numbers Differ @@ -127,7 +133,7 @@ This is the best single-number estimate for the full game right now. ### High-Value Classification Gaps -- The object rooted at `0x4588` is still not classified well enough to safely rename `0009:b1c3`. +- The object rooted at `0x4588` is still not classified well enough to safely rename the callback object itself beyond the current allocator-side glue names. - `ASYLUM.24` is only known as an import site, not yet a confidently identified routine. - Some structural names in the cache/backend/finalize cluster are waiting on object-role confirmation. @@ -194,7 +200,7 @@ Work the newest verified reset-path cluster to closure: 1. Trace more callers of `0009:b06b`. 2. Trace more callers of `FUN_0009_a961`. 3. Classify the object rooted at `0x4588`. -4. Revisit `0009:b1c3` once the object role is clearer. +4. Revisit `allocator_phase_finalize_pass` once the object role is clearer. This is currently the best next analysis target because it closes a live cluster that already has fresh verified work around it. @@ -265,7 +271,7 @@ Use these status values for subsystem maturity: ### Queue A: Highest Leverage 1. Expand the first-pass segment coverage ledger beyond the currently seeded segments. -2. Trace `0009:b06b`, `FUN_0009_a961`, and `0009:b1c3`. +2. Trace `allocator_try_alloc_from_head_table`, `allocator_head_finalize_sweep`, and `allocator_phase_finalize_pass`. 3. Identify `ASYLUM.24`. ### Queue B: Repair And Stabilize @@ -309,5 +315,5 @@ Update this file when one of the following happens: - the overall estimate changes materially, - a new subsystem reaches behavioral or stable status, -- a major blocker such as `0x4588`, `0009:b1c3`, or `ASYLUM.24` is resolved, +- a major blocker such as `0x4588`, `allocator_phase_finalize_pass`, or `ASYLUM.24` is resolved, - or the segment coverage ledger is created and becomes the new primary progress source. \ No newline at end of file