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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0x66f334fe"
|
known_hash_adler32: "0x66f334fe"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP instruction ROM for LLE audio. Free replacement (v0.4) included"
|
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"
|
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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0xf3b93527"
|
known_hash_adler32: "0xf3b93527"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP coefficient ROM for LLE audio and HLE polyphase resampling. Free replacement included"
|
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"
|
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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0x66f334fe"
|
known_hash_adler32: "0x66f334fe"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP instruction ROM for LLE audio. Free replacement included"
|
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"
|
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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0xf3b93527"
|
known_hash_adler32: "0xf3b93527"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP coefficient ROM for LLE audio and HLE polyphase resampling. Free replacement included"
|
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"
|
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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0x66f334fe"
|
known_hash_adler32: "0x66f334fe"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP instruction ROM for LLE audio. Free replacement (v0.4) included"
|
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"
|
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
|
hle_fallback: true
|
||||||
validation: [size]
|
validation: [size]
|
||||||
known_hash_adler32: "0xf3b93527"
|
known_hash_adler32: "0xf3b93527"
|
||||||
|
adler32_byteswap: true
|
||||||
note: "DSP coefficient ROM for LLE audio. Free replacement included"
|
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"
|
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.
|
# verify.py cannot reproduce these -size checks still apply if combined.
|
||||||
_CRYPTO_CHECKS = frozenset({"signature", "crypto"})
|
_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.
|
# All reproducible validation types.
|
||||||
_HASH_CHECKS = frozenset({"crc32", "md5", "sha1", "adler32"})
|
_HASH_CHECKS = frozenset({"crc32", "md5", "sha1", "adler32"})
|
||||||
|
|
||||||
@@ -72,6 +91,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
|||||||
"sha1": set(),
|
"sha1": set(),
|
||||||
"sha256": set(),
|
"sha256": set(),
|
||||||
"adler32": set(),
|
"adler32": set(),
|
||||||
|
"adler32_byteswap": False,
|
||||||
"crypto_only": set(),
|
"crypto_only": set(),
|
||||||
"emulators": set(),
|
"emulators": set(),
|
||||||
"per_emulator": {},
|
"per_emulator": {},
|
||||||
@@ -120,6 +140,8 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
|||||||
if norm.startswith("0x"):
|
if norm.startswith("0x"):
|
||||||
norm = norm[2:]
|
norm = norm[2:]
|
||||||
index[fname]["adler32"].add(norm)
|
index[fname]["adler32"].add(norm)
|
||||||
|
if f.get("adler32_byteswap"):
|
||||||
|
index[fname]["adler32_byteswap"] = True
|
||||||
# Per-emulator ground truth detail
|
# Per-emulator ground truth detail
|
||||||
expected: dict = {}
|
expected: dict = {}
|
||||||
if "size" in checks:
|
if "size" in checks:
|
||||||
@@ -225,9 +247,12 @@ def check_file_validation(
|
|||||||
expected = ",".join(sorted(entry[hash_type]))
|
expected = ",".join(sorted(entry[hash_type]))
|
||||||
return f"{hash_type} mismatch: got {hashes[hash_type]}, accepted [{expected}]"
|
return f"{hash_type} mismatch: got {hashes[hash_type]}, accepted [{expected}]"
|
||||||
if entry["adler32"]:
|
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"]))
|
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)
|
# Signature/crypto checks (3DS RSA, AES)
|
||||||
if entry["crypto_only"]:
|
if entry["crypto_only"]:
|
||||||
|
|||||||
Reference in New Issue
Block a user