capemit.py records every emitter-range write plus the DMA stream during trek draws; analyze_emit.py decodes it. Findings: TILE ids = a 13x4 grid (row<<5|col, 832/64 x 512/128); the famous SENDE block at 0x8015020 is byte-identical across captures = the fixed BACKGROUND-CLEAR program (not scene coeffs); trek's scene content lives in further payload blocks (0x8015800..0x80168c8+, many primitives) with a readable per-scanline span structure: row ids (0x39f,0x3a0,... = rows 415..422 observed), place-value indices, and edge constants in x2 chains. A first-guess parser already extracts 8 consecutive spans forming a leaning polygon edge -- rasterized geometry read directly from the compiled micro-code. Full multi-block decode + scene assembly = next session (see memory). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
2.1 KiB
Python
53 lines
2.1 KiB
Python
"""Offline decode of trek_emit.pkl: (1) DMA pairs -> per-page chains + TILE ids;
|
|
(2) emitter writes grouped by page, in address order, each word interpreted as
|
|
float / .8 fixed-point / byte fields; (3) hunt the payload structure (0x100 headers,
|
|
edge groups, z-sweeps) and candidate tile-local coordinate pairs."""
|
|
import pickle, struct, collections
|
|
S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad'
|
|
d = pickle.load(open(S + r'\trek_emit.pkl', 'rb'))
|
|
emits = d['emits']; dma = d['dma']
|
|
|
|
def asf(w):
|
|
return struct.unpack('<f', struct.pack('<I', w & 0xffffffff))[0]
|
|
|
|
# ---- DMA chains: {addr, op} pairs ----
|
|
OPS = {0x1: 'SEND', 0x9: 'SENDE', 0x2: 'TILE', 0x3: 'TXDN', 0x6: 'FLUSH',
|
|
0x0: 'GOTO', 0xf: 'STOP', 0x8: 'WAIT', 0x7: 'RETE'}
|
|
print("=== DMA stream (first 40 pairs) ===")
|
|
tiles = []
|
|
for i in range(0, min(len(dma) - 1, 80), 2):
|
|
a, op = dma[i], dma[i + 1]
|
|
code = (op >> 28) & 0xf
|
|
name = OPS.get(code, '?')
|
|
if name == 'TILE':
|
|
tiles.append(a)
|
|
if i < 80:
|
|
print(" %08x %s(%d)" % (a, name, op & 0x7f))
|
|
tile_all = [dma[i] for i in range(0, len(dma) - 1, 2)
|
|
if ((dma[i + 1] >> 28) & 0xf) == 0x2]
|
|
print("TILE ids in stream: %d distinct: %s" %
|
|
(len(tile_all), sorted(set(tile_all))[:30]))
|
|
|
|
# ---- emitter writes grouped by page ----
|
|
bypage = collections.defaultdict(list)
|
|
for qi, pc, a, w in emits:
|
|
bypage[a >> 12].append((a, w, pc))
|
|
print("\n=== pages: %s ===" % {hex(k << 12): len(v) for k, v in bypage.items()})
|
|
|
|
# dump the densest page in address order
|
|
page, rows = max(bypage.items(), key=lambda kv: len(kv[1]))
|
|
rows = sorted(set((a, w) for a, w, pc in rows))
|
|
print("\n=== densest page %#x: %d words ===" % (page << 12, len(rows)))
|
|
for a, w in rows[:90]:
|
|
f = asf(w)
|
|
e = (w >> 23) & 0xff
|
|
notes = []
|
|
if 1e-5 < abs(f) < 1e5 and 1 < e < 254:
|
|
notes.append("f=%.5g" % f)
|
|
if 0 < w < 0x10000:
|
|
notes.append("/256=%.2f" % (w / 256.0))
|
|
b = [(w >> s) & 0xff for s in (24, 16, 8, 0)]
|
|
if all(x < 0x80 for x in b) and any(x for x in b):
|
|
notes.append("bytes=%s" % b)
|
|
print(" %08x: %08x %s" % (a, w, " ".join(notes)))
|