Decode the tie LOD block: it is a table of 16-byte records

The tie block's word at +0x00 was read as an element count, and the reading
failed in a way worth recording: the payload length divided by it is a whole
number on 0 of 922 blocks, at any record size and any header up to 512 bytes.
That is the correct measurement of the wrong hypothesis -- the word never
described the payload.

Range measured: every LOD block of level 1 whose word is a non-zero multiple
of 16, plus the two read by hand in full.

Method: locate each block's record table in PCSX2's RAM by its twelve field
bytes, which are the only distinctive 12-byte run in a block, then compare
every record against its disc copy. Each block has several copies in RAM, and
the one that matches is the loaded one -- checking the first hit is what made
the first attempt report 0 of 16.

Result: on 16 of 16 blocks, every record's leading word has become
table_address + word, and the other twelve bytes are byte-identical to the
disc. So a block is [16-byte header][record table][vertex payload], the records
are 16 bytes -- a leading u32 pointer plus twelve bytes of fields -- and the
header's word at +0x00 is the byte offset from the block start to the payload,
that is, the length of the table.

That is what the multiple-of-16 was: the table holds 16-byte records. It is
never zero because there is always at least the first record, and its 42
distinct values are table lengths. Each record's pointer is relative to the
table start, relocated at load to table + word.

TieBlockHeader::data_offset and TieBlockHeader::records carry it, bound by the
offset, with TieRecord for the twelve field bytes, and the disc test asserts
the table is bounded on every block. What the records' fields name and what the
payload holds are still open -- the payload is known to be variable-length,
float-shaped, not LZ77 and not VIF1.
This commit is contained in:
2026-10-12 07:17:41 +02:00
parent c2af0528e3
commit e6eecb871f
4 changed files with 181 additions and 12 deletions
+35
View File
@@ -1194,6 +1194,41 @@ guess; that it is two fields is not.
Combined with block sizes always being multiples of 16, that rules out a uniform
stride without a header.
## tie: the block is a table of 16-byte records (from RAM)
**Range measured:** every tie LOD block of level 1 whose leading word is a
non-zero multiple of 16 -- 16 blocks -- plus the two read by hand in full.
**Method:** locate each block's record table in PCSX2's RAM by its twelve field
bytes (the records are the only part of a block with a distinctive 12-byte
run), then compare every record against its disc copy. Each block has several
copies in RAM; the one that matches is the loaded copy.
**Result: on 16 of 16 blocks, every record's leading word has become
`table_address + word`, and the other twelve bytes are byte-identical to the
disc.** So:
- A block is `[16-byte header][record table][vertex payload]`, and the records
are **16 bytes**: a leading `u32` pointer and twelve bytes of fields.
- The header's word at `+0x00` is the **byte offset from the block start to
the vertex payload** -- that is, the length of the record table. This is what
the "count" reading was groping at: it is a multiple of 16 on all 2,177 blocks
because the table holds 16-byte records, it is never zero because there is
always at least the header-sized first record, and its 42 distinct values are
table lengths, not counts of anything in the payload.
- Every record's leading word is a pointer **relative to the start of the record
table**, relocated at load to `table + word`. The twelve field bytes are
copied verbatim.
This also explains the dead end that ran before it. The payload length divided
by the word at `+0x00` is a whole number on **0 of 922** blocks, at any record
size and any header up to 512 bytes -- which is the correct measurement of the
wrong hypothesis: the word never described the payload, it described where the
payload starts. A count of what follows a pointer is not the pointer.
`TieBlockHeader::data_offset` and `TieBlockHeader::records` carry it, bound by
the offset, and the disc test asserts the table is bounded on every block.
### What the payload is, and what retired the coordinate reading
The payload is **not random**, and that took a control to establish. Reading each