"""Differential test of the lifter on the game's own instructions: lifted C against Unicorn, one instruction at a time. Samples distinct instruction words from the .text of each ExeFS module, one per opcode signature first, lifts each with the portable FP/SIMD lowering, runs it from random register state, and compares X0-X30, SP, NZCV, PC (for branches), V0-V31 and the scratch buffer (for loads and stores) with Unicorn as a Cortex-A57. Skipped: system instructions and exceptions, whose single step cannot be compared, and exclusives and ARMv8.1 atomics, which atomic.py covers. Encodings the lifter rejects are counted per module and mnemonic; --coverage lifts every distinct word instead of testing. Adapted from LAS Recomp tools/test_lift.py @ da35b83 (MIT, Copyright (c) 2026 Peiikai). Usage: lift.py [--exefs DIR] [--modules main,sdk,subsdk0] [--encodings N] [--cases K] [--seed S] [--jobs J] lift.py --coverage """ import argparse import os import platform import random import sys import time import zlib from collections import Counter from pathlib import Path import numpy as np import unicorn as uc from common import BUF, BUF_SIZE, ROOT, Emu, build_harness, diff_state, dis, mnemonic, rand_fpcr, rand_v, rand_x, \ run_harness from lifter import Lifter, Unsupported, bits from nso import Nso BUF_MID = BUF + 0x10000 # Test load addresses, below 2^39 and clear of BUF. BASES = {'main': 0x7000000000, 'subsdk0': 0x7008000000, 'sdk': 0x7010000000} def is_mem(w): return bits(w, 25, 1) == 0 and bits(w, 27, 1) == 1 def classify(w): """'skip' for instructions whose single-step behaviour cannot be compared.""" if (w & 0xFFC00000) == 0xD5000000: # system: hints, barriers, MRS/MSR, cache maintenance return 'skip' if (w & 0x3F000000) == 0x08000000 and (bits(w, 23, 1) == 0 or bits(w, 21, 1)): return 'skip' # exclusives need a paired load; CAS is ARMv8.1; both are covered by atomic.py if (w & 0x3F200C00) == 0x38200000: # LSE atomics, ARMv8.1: atomic.py return 'skip' if (w & 0xFF000000) == 0xD4000000: # SVC, BRK, HLT return 'skip' if (w & 0xFFFF0000) == 0: # UDF return 'skip' return 'ok' def class_keys(words): """Opcode signature per word: register fields (Rd, Rn, Rm) cleared.""" return words & np.uint32(0xFFE0FC00) def to_test_body(ins, pc): if ins.kind == 'op': return ins.code nxt = f'0x{pc + 4:x}ull' if ins.kind == 'b': return f'c->pc = 0x{ins.target:x}ull;' if ins.kind == 'bl': return f'c->x[30] = {nxt}; c->pc = 0x{ins.target:x}ull;' if ins.kind == 'bcond': return f'c->pc = ({ins.cond}) ? 0x{ins.target:x}ull : {nxt};' if ins.kind == 'br': return f'c->pc = {ins.target};' if ins.kind == 'blr': return f'{{ uint64_t t = {ins.target}; c->x[30] = {nxt}; c->pc = t; }}' if ins.kind == 'ret': return 'c->pc = c->x[30];' raise Unsupported(ins.kind) def pick_module(name, nso, base, count, r, unsupported): """Distinct words of .text, one per opcode signature first, lifted. Returns [(word, pc, body)].""" lo, size = nso.text words = np.frombuffer(bytes(nso.image[lo:lo + size]), dtype='= count: break w = int(uniq[i]) if classify(w) == 'skip': continue pc = base + lo + int(first[i]) * 4 try: body = to_test_body(lifter.lift(w, pc), pc) except Unsupported: unsupported[(name, mnemonic(w))] += 1 continue picks.append((w, pc, body)) print(f'{name}: {len(words)} words, {len(uniq)} distinct, {len(seen)} signatures, {len(picks)} picked') return picks def coverage(name, nso, base): """Lift every distinct word of .text. Returns {kind mnemonic: [distinct words, occurrences]} of words the lifter rejects (Unsupported) or turns into an undefined-instruction trap (rt_udf).""" lo, size = nso.text words = np.frombuffer(bytes(nso.image[lo:lo + size]), dtype='