trekframe.py parses the captured payload blocks (0x100 headers, rowid words 0x300|row, packed edge fields) into per-scanline spans and composites them onto an 832x512 canvas -- 21 blocks / 124 spans from the trek demo's compiled stream: distinct multi-colored objects + slanted band elements. dumppay.py dumps the payload region at chosen draws (scene verified byte-identical draws 1-300 = compile-once static showcase). Readout gains §06 with the frame rendered from the span data. First-approximation decode (edge-field scaling still being pinned) -- but every mark is a span the firmware's rasteriser emitted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
104 lines
3.7 KiB
Python
104 lines
3.7 KiB
Python
"""THE TREK FRAME, first assembly: parse every content payload block in trek_emit.pkl
|
|
(pages 0x8015800-0x8017fff, skipping the fixed background at 0x8015000-7ff), extract
|
|
per-scanline span groups {rowid 0x300|row, packed edge words}, and composite all spans
|
|
onto an 832x512 canvas (x = C*4 hypothesis). Each block gets its own shade. PNG out."""
|
|
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']
|
|
|
|
def asf(w):
|
|
return struct.unpack('<f', struct.pack('<I', w & 0xffffffff))[0]
|
|
|
|
# content words in address order, deduped (last write wins per address)
|
|
mem = {}
|
|
for qi, pc, a, w in emits:
|
|
if 0x08015800 <= a < 0x08018000:
|
|
mem[a] = w
|
|
addrs = sorted(mem)
|
|
print("content words: %d span %#x..%#x" % (len(addrs), addrs[0], addrs[-1]))
|
|
|
|
# split into blocks at 0x00000100 headers
|
|
blocks = []
|
|
cur = None
|
|
for a in addrs:
|
|
w = mem[a]
|
|
if w == 0x100 and (cur is None or a - cur[-1][0] > 4 or len(cur) > 3):
|
|
if cur: blocks.append(cur)
|
|
cur = []
|
|
if cur is not None:
|
|
cur.append((a, w))
|
|
if cur: blocks.append(cur)
|
|
print("blocks found: %d sizes: %s" % (len(blocks), [len(b) for b in blocks][:20]))
|
|
|
|
# parse each block: rowid words (0x300..0x6ff) delimit row groups; collect byte-3
|
|
# fields of packed words within the group as edge coordinates
|
|
def parse_block(blk):
|
|
spans = []
|
|
row = None
|
|
edges = []
|
|
for a, w in blk:
|
|
if 0x300 <= w <= 0x6ff:
|
|
if row is not None and edges:
|
|
spans.append((row & 0x1ff, min(edges), max(edges)))
|
|
row = w
|
|
edges = []
|
|
elif row is not None:
|
|
f = asf(w)
|
|
if 1e-5 < abs(f) < 1e3 and 1 < ((w >> 23) & 0xff) < 254:
|
|
continue # increment float
|
|
if w == 0xec00 or w == 0x100:
|
|
continue # constants
|
|
b3 = w & 0xff
|
|
b2 = (w >> 8) & 0xff
|
|
if (w >> 16) & 0xff <= 0x20 and 0 < b3 <= 250:
|
|
edges.append(b3)
|
|
if row is not None and edges:
|
|
spans.append((row & 0x1ff, min(edges), max(edges)))
|
|
return spans
|
|
|
|
W, H = 832, 512
|
|
canvas = [[0] * W for _ in range(H)]
|
|
total = 0
|
|
for bi, blk in enumerate(blocks):
|
|
spans = parse_block(blk)
|
|
total += len(spans)
|
|
shade = (bi % 6) + 2
|
|
for row, c1, c2 in spans:
|
|
if not (0 <= row < H):
|
|
continue
|
|
x1 = max(0, min(W - 1, c1 * 4)); x2 = max(0, min(W - 1, c2 * 4))
|
|
for x in range(min(x1, x2), max(x1, x2) + 1):
|
|
canvas[row][x] = shade
|
|
if spans:
|
|
rs = [s[0] for s in spans]
|
|
print(" block %2d @%#x: %3d spans rows[%d..%d]" %
|
|
(bi, blk[0][0], len(spans), min(rs), max(rs)))
|
|
print("total spans: %d" % total)
|
|
|
|
# ASCII preview
|
|
print("\nFRAME (832x512 -> 104x40):")
|
|
for y in range(0, H, H // 40):
|
|
line = ""
|
|
for x in range(0, W, W // 104):
|
|
v = canvas[y][x]
|
|
line += " .:-=+*#%@"[min(9, v)] if v else " "
|
|
print(" " + line)
|
|
|
|
# PNG via PPM
|
|
img = bytearray(W * H * 3)
|
|
PAL = [(7, 11, 17), (20, 30, 40), (65, 255, 142), (95, 208, 255), (255, 176, 32),
|
|
(255, 90, 106), (234, 255, 239), (160, 120, 255), (200, 200, 90), (90, 200, 160)]
|
|
for y in range(H):
|
|
for x in range(W):
|
|
r_, g_, b_ = PAL[min(9, canvas[y][x])]
|
|
o = (y * W + x) * 3
|
|
img[o], img[o + 1], img[o + 2] = r_, g_, b_
|
|
open(S + r'\trekframe.ppm', 'wb').write(b'P6\n%d %d\n255\n' % (W, H) + bytes(img))
|
|
try:
|
|
from PIL import Image
|
|
Image.open(S + r'\trekframe.ppm').save(S + r'\trekframe.png')
|
|
print("wrote trekframe.png")
|
|
except Exception as e:
|
|
print("ppm only:", e)
|