mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
An 82-byte payload written in GSPA assembly, linked at bit 01800000h and loaded into main RAM by harness/mame/hello.lua, executes on the CPU: it writes DEAD/BEEF and a 1024-iteration counter into RAM and fills a 256x64 block in video RAM, which appears in the frame dump at x 256..511, y 136..199. Entry is a debugger breakpoint on the level-0 menu idle loop, not a delivery mechanism. Includes the build script, a COFF .text extractor (gsprom's hex addresses wrap at 64 KB), the run log, RAM excerpt, frame crops including a no-load control, and HELLO_WORLD_REPORT.md.
54 lines
2.1 KiB
Python
Executable File
54 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Extract the first loadable section of a TI GSP COFF file as raw bytes.
|
|
|
|
GSPLNK writes a COFF whose section header carries the FULL 32-bit bit
|
|
address in `paddr`, so placement does not depend on gsprom's hex output
|
|
(whose addresses wrap at 64 KB -- documented in reference/tms34010-sdk.md).
|
|
|
|
Usage: cofextract.py hello.out payload.bin
|
|
Prints: origin=<bit address> size=<bytes> file_offset=<hex>
|
|
"""
|
|
import struct
|
|
import sys
|
|
|
|
# TI TMS34010 COFF: 20-byte file header, optional header size in the header.
|
|
# Section header: name[8] paddr(4) vaddr(4) size(4) scnptr(4) relptr(4)
|
|
# lnnoptr(4) nreloc(2) nlnno(2) flags(4) = 40 bytes
|
|
def main(out_path, bin_path):
|
|
d = open(out_path, "rb").read()
|
|
if len(d) < 20:
|
|
sys.exit("cofextract: file too short")
|
|
magic, nscns, _timdat, _symptr, _nsyms, opthdr, _flags = struct.unpack_from(
|
|
"<HHIIIHH", d, 0)
|
|
if magic != 0x0090:
|
|
sys.exit("cofextract: unexpected COFF magic %#06x" % magic)
|
|
base = 20 + opthdr
|
|
secs = []
|
|
for i in range(nscns):
|
|
off = base + i * 40
|
|
name = d[off:off + 8].rstrip(b"\0").decode("latin1")
|
|
paddr, vaddr, size, scnptr, _relptr, _lnnoptr, _nreloc, _nlnno, flags = \
|
|
struct.unpack_from("<IIIIIIHHI", d, off + 8)
|
|
secs.append((name, paddr, size, scnptr, flags))
|
|
# .text is the only initialized section GSPLNK emits for our payload.
|
|
text = [s for s in secs if s[0] == ".text"]
|
|
if not text:
|
|
sys.exit("cofextract: no .text section")
|
|
name, paddr, size, scnptr, _flags = text[0]
|
|
# size and paddr are bit units; bytes = size >> 3.
|
|
nbytes = size >> 3
|
|
payload = d[scnptr:scnptr + nbytes]
|
|
if len(payload) != nbytes:
|
|
sys.exit("cofextract: truncated section (%d of %d bytes)"
|
|
% (len(payload), nbytes))
|
|
open(bin_path, "wb").write(payload)
|
|
print("origin=%08X size=%d file_offset=%#x md5=%s" % (
|
|
paddr, nbytes, scnptr,
|
|
__import__("hashlib").md5(payload).hexdigest()))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 3:
|
|
sys.exit("usage: cofextract.py hello.out payload.bin")
|
|
main(sys.argv[1], sys.argv[2])
|