mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-13 12:22:33 -05:00
fix: adler32 byteswap for dolphin dsp validation
Dolphin computes adler32 on byte-swapped (16-bit) data, not raw file bytes. Add adler32_byteswap flag to dolphin/primehack/ishiiruka profiles and support it in validation.py. Reduces hash mismatch discrepancies from 18 to 2.
This commit is contained in:
@@ -65,6 +65,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0x66f334fe"
|
||||
adler32_byteswap: true
|
||||
note: "DSP instruction ROM for LLE audio. Free replacement (v0.4) included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:136, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:84-117"
|
||||
|
||||
@@ -75,6 +76,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0xf3b93527"
|
||||
adler32_byteswap: true
|
||||
note: "DSP coefficient ROM for LLE audio and HLE polyphase resampling. Free replacement included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:137, Source/Core/Core/DSP/DSPCore.cpp:32-33, Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp:55-62"
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0x66f334fe"
|
||||
adler32_byteswap: true
|
||||
note: "DSP instruction ROM for LLE audio. Free replacement included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:112, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:142-150, Source/Core/Core/DSP/DSPCore.cpp:48,67"
|
||||
|
||||
@@ -72,6 +73,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0xf3b93527"
|
||||
adler32_byteswap: true
|
||||
note: "DSP coefficient ROM for LLE audio and HLE polyphase resampling. Free replacement included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:113, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:143-153, Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp:43-72, Source/Core/Core/DSP/DSPCore.cpp:48,68"
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0x66f334fe"
|
||||
adler32_byteswap: true
|
||||
note: "DSP instruction ROM for LLE audio. Free replacement (v0.4) included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:135, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:87-117"
|
||||
|
||||
@@ -79,6 +80,7 @@ files:
|
||||
hle_fallback: true
|
||||
validation: [size]
|
||||
known_hash_adler32: "0xf3b93527"
|
||||
adler32_byteswap: true
|
||||
note: "DSP coefficient ROM for LLE audio. Free replacement included"
|
||||
source_ref: "Source/Core/Common/CommonPaths.h:136, Source/Core/Core/DSP/DSPCore.cpp:32-38"
|
||||
|
||||
|
||||
@@ -15,6 +15,25 @@ from common import compute_hashes
|
||||
# verify.py cannot reproduce these -size checks still apply if combined.
|
||||
_CRYPTO_CHECKS = frozenset({"signature", "crypto"})
|
||||
|
||||
|
||||
def _adler32_byteswapped(path: str) -> str:
|
||||
"""Compute adler32 on 16-bit byte-swapped data.
|
||||
|
||||
Dolphin's DSP loader swaps every 16-bit word before hashing
|
||||
(Common::swap16 in DSPLLE.cpp:LoadDSPRom). This reproduces that
|
||||
transform so verify.py can match the expected adler32 values.
|
||||
"""
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
with open(path, "rb") as f:
|
||||
data = f.read()
|
||||
# Pad to even length if necessary
|
||||
if len(data) % 2:
|
||||
data += b"\x00"
|
||||
swapped = struct.pack(f">{len(data) // 2}H", *struct.unpack(f"<{len(data) // 2}H", data))
|
||||
return format(zlib.adler32(swapped) & 0xFFFFFFFF, "08x")
|
||||
|
||||
# All reproducible validation types.
|
||||
_HASH_CHECKS = frozenset({"crc32", "md5", "sha1", "adler32"})
|
||||
|
||||
@@ -72,6 +91,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
"sha1": set(),
|
||||
"sha256": set(),
|
||||
"adler32": set(),
|
||||
"adler32_byteswap": False,
|
||||
"crypto_only": set(),
|
||||
"emulators": set(),
|
||||
"per_emulator": {},
|
||||
@@ -120,6 +140,8 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
if norm.startswith("0x"):
|
||||
norm = norm[2:]
|
||||
index[fname]["adler32"].add(norm)
|
||||
if f.get("adler32_byteswap"):
|
||||
index[fname]["adler32_byteswap"] = True
|
||||
# Per-emulator ground truth detail
|
||||
expected: dict = {}
|
||||
if "size" in checks:
|
||||
@@ -225,9 +247,12 @@ def check_file_validation(
|
||||
expected = ",".join(sorted(entry[hash_type]))
|
||||
return f"{hash_type} mismatch: got {hashes[hash_type]}, accepted [{expected}]"
|
||||
if entry["adler32"]:
|
||||
if hashes["adler32"].lower() not in entry["adler32"]:
|
||||
actual_adler = hashes["adler32"].lower()
|
||||
if entry.get("adler32_byteswap"):
|
||||
actual_adler = _adler32_byteswapped(local_path)
|
||||
if actual_adler not in entry["adler32"]:
|
||||
expected = ",".join(sorted(entry["adler32"]))
|
||||
return f"adler32 mismatch: got 0x{hashes['adler32']}, accepted [{expected}]"
|
||||
return f"adler32 mismatch: got 0x{actual_adler}, accepted [{expected}]"
|
||||
|
||||
# Signature/crypto checks (3DS RSA, AES)
|
||||
if entry["crypto_only"]:
|
||||
|
||||
Reference in New Issue
Block a user