Preserve formatted NAND boot and Wii Remote pairing, add DMA/SRAM conformance tests and a Wii comparison probe. Keep P1 profiling tools and native update A/B evidence; reject the unhelpful targeted SRAM shortcut.
80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare two runs of the identical Wii conformance DOL."""
|
|
|
|
import argparse
|
|
import csv
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
METADATA = ("schema", "rounds", "observations", "ios_version", "ios_revision")
|
|
HEADER = ["seq", "test", "round", "value", "extra"]
|
|
|
|
|
|
def read_capture(path: Path):
|
|
with path.open(newline="", encoding="utf-8") as stream:
|
|
rows = csv.reader(stream)
|
|
metadata = {}
|
|
for key in METADATA:
|
|
row = next(rows, None)
|
|
if row is None or len(row) != 2 or row[0] != key:
|
|
raise ValueError(f"{path}: expected metadata row {key!r}")
|
|
metadata[key] = int(row[1])
|
|
if next(rows, None) != HEADER:
|
|
raise ValueError(f"{path}: invalid observation header")
|
|
observations = []
|
|
for line, row in enumerate(rows, start=7):
|
|
if len(row) != 5:
|
|
raise ValueError(f"{path}:{line}: expected 5 columns")
|
|
seq, test, round_number, value, extra = row
|
|
if int(seq) != len(observations):
|
|
raise ValueError(f"{path}:{line}: sequence is not contiguous")
|
|
observations.append((test, int(round_number), int(value), int(extra)))
|
|
if len(observations) != metadata["observations"]:
|
|
raise ValueError(
|
|
f"{path}: expected {metadata['observations']} observations, "
|
|
f"found {len(observations)}"
|
|
)
|
|
return metadata, observations
|
|
|
|
|
|
def compare(reference, candidate, limit=20):
|
|
reference_meta, reference_rows = reference
|
|
candidate_meta, candidate_rows = candidate
|
|
for key in METADATA:
|
|
if reference_meta[key] != candidate_meta[key]:
|
|
print(f"Incomparable runs: {key}: Wii={reference_meta[key]}, Dolphin={candidate_meta[key]}")
|
|
return 2
|
|
|
|
differences = 0
|
|
for index in range(max(len(reference_rows), len(candidate_rows))):
|
|
expected = reference_rows[index] if index < len(reference_rows) else None
|
|
actual = candidate_rows[index] if index < len(candidate_rows) else None
|
|
if expected == actual:
|
|
continue
|
|
differences += 1
|
|
if differences <= limit:
|
|
print(f"#{index} Wii={expected} Dolphin={actual}")
|
|
|
|
if differences:
|
|
print(f"{differences} differences across {max(len(reference_rows), len(candidate_rows))} observations")
|
|
return 1
|
|
print(f"Identical: {len(reference_rows)} observations")
|
|
return 0
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("wii", type=Path, help="CSV from the real Wii")
|
|
parser.add_argument("dolphin", type=Path, help="CSV from Dolphin")
|
|
args = parser.parse_args()
|
|
try:
|
|
return compare(read_capture(args.wii), read_capture(args.dolphin))
|
|
except (OSError, ValueError) as error:
|
|
print(error, file=sys.stderr)
|
|
return 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|