#!/usr/bin/env python3 # parseTrace.py - turn a raw VICE tracepoint log from testHarden.py into an ordered access list and # a per-address / per-page census. # # python3 parseTrace.py testLogs/harden.de00.A.cold.txt [more logs ...] # # The monitor announces a tracepoint hit as a header line and then disassembles the instruction that # caused it, with the CPU registers after it executed: # # #1 (Trace store de03) 40/$028, 50/$32 # .C:e567 8D 03 DE STA $DE03 - A:1E X:00 Y:24 SP:ed ..-..... 213365345 # # For a store, A is the byte written; for a load, A is the byte read. Note that VICE prints the # register values with UPPERCASE hex digits and the program counter with lowercase ones, which is # the sort of detail that silently drops every access whose value contains A-F if the pattern only # allows one case. import re import sys TRACE_HEAD = re.compile(r"#(\d+)\s+\(Trace\s+(\w+)\s+([0-9a-f]{4})\)") DISASM = re.compile(r"\.C:([0-9a-f]{4})\s+((?:[0-9A-F]{2} )+)\s*(\S+)\s+(\S*)\s*-\s*A:([0-9A-Fa-f]{2})") def parse(text): events = [] lines = text.splitlines() for index, line in enumerate(lines): head = TRACE_HEAD.search(line) if not head: continue hit = DISASM.search(lines[index + 1]) if index + 1 < len(lines) else None events.append({"kind": head.group(2), "addr": int(head.group(3), 16), "pc": int(hit.group(1), 16) if hit else None, "op": hit.group(3) if hit else "?", "a": int(hit.group(5), 16) if hit else None}) return events def census(events): counts = {} pages = {} for event in events: counts[(event["addr"], event["kind"])] = counts.get((event["addr"], event["kind"]), 0) + 1 page = event["addr"] & 0xFF00 pages[page] = pages.get(page, 0) + 1 return counts, pages def main(): for path in sys.argv[1:]: events = parse(open(path, encoding="latin-1").read()) counts, pages = census(events) print(f"=== {path}: {len(events)} accesses ===") unpaired = [e for e in events if e["a"] is None] if unpaired: print(f" WARNING: {len(unpaired)} headers had no disassembly line after them") for addr, kind in sorted(counts): print(f" ${addr:04X} {kind:5s} x {counts[(addr, kind)]}") for page in sorted(pages): print(f" page ${page:04X}: {pages[page]} accesses") first = events[:14] print(" first accesses, in order:") for event in first: print(f" {event['kind']:5s} ${event['addr']:04X} {event['op']} at " f"${event['pc']:04X} A=${event['a']:02X}") ctrl = [e for e in events if e["kind"] == "store" and (e["addr"] & 0x00FF) == 3] print(f" every control-register write, in order: " f"{' '.join('$%02X' % e['a'] for e in ctrl)}") if __name__ == "__main__": main()