#!/usr/bin/env python3 # Ch352 diagnostic (Codex's test): replace the SH3 texture indices with a LARGE, UNMISTAKABLE # 16x16-cell pattern using strongly-contrasting indices from the REAL SH3 CSM1 palette, and emit it # through the EXACT same linear LPDDR texture file the uploader streams. Geometry / CLUT / feeder are # untouched. If the cells render as clean flat colors -> the board photo is authentic high-frequency # SH3 texture, NOT timing corruption. If the flat cells speckle -> real corruption. # # LOCAL/gitignored (palette is dump-derived). Backs up the real texture to *.REAL.bak first. import sys, os sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from gs_localmem import ct32_addr # CT32 grid de-swizzle (CSM1 palette layout) DATA = os.path.join(os.path.dirname(__file__), "..", "sim", "data", "top_psmct32_raster_demo") TEX = os.path.join(DATA, "sh3_real_tex_lpddr.mem") CLUT = os.path.join(DATA, "sh3_real_clut.mem") TW = TH = 512 CELL = 16 NCHOSEN = 8 def load_words(path): out = [] with open(path) as f: for ln in f: s = ln.strip() if not s or s.startswith("/"): continue out.append(int(s, 16) & 0xFFFFFFFF) return out # ---- 1) de-grid the CSM1 palette to index order, get each index's RGB ---- clut_words = load_words(CLUT) clut_bytes = bytearray() for w in clut_words: clut_bytes += (w & 0xFFFFFFFF).to_bytes(4, "little") pal = [0]*256 for i in range(256): a = ct32_addr(0, 1, i & 15, i >> 4) # palette entry i sits at grid (i%16, i//16) pal[i] = int.from_bytes(clut_bytes[a:a+4], "little") if a+4 <= len(clut_bytes) else 0 rgb = [(p & 0xFF, (p >> 8) & 0xFF, (p >> 16) & 0xFF) for p in pal] # PSMCT32 low byte = R # ---- 2) greedy farthest-point pick of NCHOSEN maximally-contrasting indices ---- def d2(a, b): return sum((a[k]-b[k])**2 for k in range(3)) chosen = [max(range(256), key=lambda i: rgb[i][0]+rgb[i][1]+rgb[i][2])] # start brightest while len(chosen) < NCHOSEN: nxt = max(range(256), key=lambda i: min(d2(rgb[i], rgb[c]) for c in chosen)) chosen.append(nxt) print("[banded] chosen indices + RGB:", [(c, rgb[c]) for c in chosen]) # ---- 3) build the 16x16-cell pattern as LINEAR raster indices (PSMT8_SWIZZLE=0) ---- idx = bytearray(TW*TH) for y in range(TH): cy = y // CELL for x in range(TW): cx = x // CELL idx[y*TW + x] = chosen[(cx + cy) % NCHOSEN] # diagonal bands of contrasting flat cells # ---- 4) pack 4 indices / LE word, write through the exact uploader format ---- if os.path.exists(TEX) and not os.path.exists(TEX + ".REAL.bak"): os.rename(TEX, TEX + ".REAL.bak") print("[banded] backed up real texture ->", os.path.basename(TEX) + ".REAL.bak") nwords = (TW*TH)//4 with open(TEX, "w") as f: f.write("// Ch352 DIAGNOSTIC banded 16x16-cell texture (contrasting SH3 palette indices). " "LINEAR de-swizzled, PSMT8_SWIZZLE=0. Restore from sh3_real_tex_lpddr.mem.REAL.bak. gitignored.\n") sm = 0 for w in range(nwords): word = idx[4*w] | (idx[4*w+1] << 8) | (idx[4*w+2] << 16) | (idx[4*w+3] << 24) sm = (sm + word) & 0xFFFFFFFF f.write("%08x\n" % word) print(f"[banded] wrote {nwords} words to {TEX} sum32=0x{sm:08x}") print("[banded] upload as usual; on HDMI expect a perspective-warped grid of FLAT contrasting cells.") print("[banded] CLEAN flat cells => authentic texture (not corruption). SPECKLED cells => real corruption.")