Emit-stream capture + first span read-out from a live scene (trek)
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>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
"""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)))
|
||||
@@ -0,0 +1,62 @@
|
||||
"""THE capture: during 2 trek draws record (a) every w32 issued from the EMITTER range
|
||||
(0xf041d000-0xf041e000): (pc, addr, word) -- the compiled micro-code with tile-local
|
||||
coords packed in 8-bit fields; (b) every DMA-list pair from the coeff-copy
|
||||
(0xf0411cd4): the TILE(id)/GOTO(link) entries that map queue pages -> tile ids.
|
||||
Save both streams to trek_emit.pkl for offline decode + scene reconstruction."""
|
||||
import sys, time, struct, pickle
|
||||
sys.path.insert(0, r'C:\VWE\TeslaRel410\emulator\firmware-decomp')
|
||||
sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha')
|
||||
import emu860, dis860, emu_main
|
||||
emu860.Mem.log = lambda self, *a, **k: None
|
||||
S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad'
|
||||
snap = pickle.load(open(S + r'\snap_trek0.pkl', 'rb'))
|
||||
r = emu_main.MainRunner(r'C:\VWE\TeslaRel410\dpl3-revive\patha\trek.raw.bin',
|
||||
fw='capfw7', max_cmds=30000)
|
||||
cpu = r.cpu
|
||||
cpu.mem.pages = {k: bytearray(v) for k, v in snap['pages'].items()}
|
||||
cpu.ctrl.clear(); cpu.ctrl.update(snap['ctrl'])
|
||||
cpu.r = list(snap['r']); cpu.f = list(snap['f']); cpu.cr = dict(snap['cr']); cpu.pc = snap['pc']
|
||||
cpu._apipe = list(snap['apipe']); cpu._mpipe = list(snap['mpipe']); cpu._fp_pipes()
|
||||
cpu._lpipe = list(snap['lpipe']); cpu._gpipe = list(snap['gpipe'])
|
||||
cpu._kr, cpu._ki, cpu._t = snap['kr'], snap['ki'], snap['t']
|
||||
cpu.lcc = snap['lcc']; r.qi = snap['qi']; r.heap = list(snap['heap'])
|
||||
|
||||
ELO, EHI = 0xf041d000, 0xf041e000
|
||||
COPY = 0xf0411cd4
|
||||
emits = [] # (qi, pc, addr, word)
|
||||
dma = [] # copy words in order (pairs)
|
||||
orig = emu860.Mem.w32
|
||||
def w32(self, addr, val):
|
||||
pc = cpu.pc
|
||||
if ELO <= pc < EHI:
|
||||
emits.append((r.qi, pc, addr & 0xffffffff, val & 0xffffffff))
|
||||
elif pc == COPY:
|
||||
dma.append(val & 0xffffffff)
|
||||
return orig(self, addr, val)
|
||||
emu860.Mem.w32 = w32
|
||||
t0 = time.time(); startq = r.qi
|
||||
while time.time() - t0 < 300:
|
||||
if r.qi >= startq + 4: break
|
||||
h = r.hooks.get(cpu.pc)
|
||||
if h:
|
||||
if h(cpu) == 'done': break
|
||||
continue
|
||||
if not cpu.step(): break
|
||||
emu860.Mem.w32 = orig
|
||||
|
||||
print("emitter writes: %d dma words: %d (cmds %d..%d)" %
|
||||
(len(emits), len(dma), startq, r.qi))
|
||||
pickle.dump({'emits': emits, 'dma': dma}, open(S + r'\trek_emit.pkl', 'wb'))
|
||||
print("saved trek_emit.pkl")
|
||||
|
||||
# quick preview: field spectrum of the packed words
|
||||
import collections
|
||||
b0 = collections.Counter(); b1 = collections.Counter()
|
||||
pages = collections.Counter()
|
||||
for qi, pc, a, w in emits:
|
||||
b0[w & 0xff] += 1
|
||||
b1[(w >> 8) & 0xff] += 1
|
||||
pages[a >> 12] += 1
|
||||
print("distinct target pages:", len(pages))
|
||||
print("byte0 spectrum (top 12):", dict(b0.most_common(12)))
|
||||
print("byte1 spectrum (top 12):", dict(b1.most_common(12)))
|
||||
Reference in New Issue
Block a user