From b95bf466e87404dff9d8620ed5b92ed9ad610d46 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 27 Oct 2026 15:52:29 +0100 Subject: [PATCH] feat: add the PlayStation reference frames Bust-A-Move 2 (USA) on Beetle PSX, Beetle PSX HW, SwanStation, PCSX-ReARMed and PCSX1, each frame reviewed on its PNG. A boot needs a screen of the game: the BIOS screens alone are not one. --- scripts/core_probe.py | 21 ++++-- tests/campaign/oracle.yml | 149 +++++++++++++++++++++++++++++++++++++- tests/test_core_probe.py | 10 ++- 3 files changed, 172 insertions(+), 8 deletions(-) diff --git a/scripts/core_probe.py b/scripts/core_probe.py index 2ce9e137e..0c6e91f45 100644 --- a/scripts/core_probe.py +++ b/scripts/core_probe.py @@ -1197,8 +1197,8 @@ def judge(rep: dict, oracle: dict) -> tuple[str, dict]: """The verdict of one repetition and the evidence that decided it. In order: a worker killed after the timeout is a hang and one that died - a crash, from the process status. A reference frame reached is a boot. - Without one, an error pattern of the core log or a known error screen + a crash, from the process status. A reference frame of the game reached + is a boot: the console's own screens alone are not. Without one, an error pattern of the core log or a known error screen is a BIOS error. Every sampled frame of the second half one colour is a hang. Anything else is unknown: a run is never called a boot because its frames differ from another run's. @@ -1217,12 +1217,23 @@ def judge(rep: dict, oracle: dict) -> tuple[str, dict]: frames.append((int(rep.get("frames", 0)) + int(rep.get("warmup", 0)), final)) references = {r["sha1"]: r for r in oracle.get("references") or ()} reached = [(frame, digest) for frame, digest in frames if digest in references] - if reached: - frame, digest = reached[0] - stages = list(dict.fromkeys(references[d]["stage"] for _, d in reached)) + stages = list(dict.fromkeys(references[d]["stage"] for _, d in reached)) + game = [(frame, digest) for frame, digest in reached if references[digest]["stage"] == "game"] + if game: + frame, digest = game[0] return BOOTS, {"rule": "reference_frame", "detail": f"frame {frame} shows {references[digest]['shows']}", "frame": frame, "sha1": digest, "stages": stages} + verdict, evidence = _without_the_game(rep, oracle, frames) + if stages: + # The console's own screens without one of the game: never a boot. + evidence["stages"] = stages + evidence["detail"] += ", after the BIOS screens and no screen of the game" + return verdict, evidence + + +def _without_the_game(rep: dict, oracle: dict, frames: list[tuple[int, str]]) -> tuple[str, dict]: + """The verdict of a run that reached no screen of the game.""" for pattern in oracle.get("error_patterns") or (): for line in rep.get("logs") or (): if re.search(pattern, line["text"]): diff --git a/tests/campaign/oracle.yml b/tests/campaign/oracle.yml index fa567f1d6..fd316c5ea 100644 --- a/tests/campaign/oracle.yml +++ b/tests/campaign/oracle.yml @@ -21,6 +21,151 @@ error_patterns: [] -cores: {} +cores: + # The PlayStation cores below log a missing or wrong BIOS and boot a + # built-in one: none of those lines is an error pattern. + "Beetle PSX": + note: >- + A missing BIOS logs "Firmware is missing" and loads the embedded + OpenBIOS, a wrong one logs "Firmware found but has invalid SHA1" and is + loaded anyway (libretro.c:849, 856, 3504-3511 at 7fea57a5). + error_patterns: [] + error_screens: [] + "Beetle PSX HW": + note: The same code as Beetle PSX, built with the hardware renderers. + error_patterns: [] + error_screens: [] + "SwanStation": + note: >- + "No BIOS image found for region" is followed by the built-in + OpenBIOS (src/core/host_interface.cpp:182, src/core/system.cpp:678-682 + at 631f0fb3). + error_patterns: [] + error_screens: [] + "PCSX-ReARMed": + note: >- + Without a BIOS, or with one of the wrong size, it logs "Using HLE BIOS" + and runs its own (frontend/libretro.c:3893-3899 at c8816799). The BIOS + boot logo is off by default (pcsx_rearmed_show_bios_bootlogo), so its + runs reach no bios-stage screen. + error_patterns: [] + error_screens: [] + "PCSX1": + note: An HLE BIOS stands in when none is found, and the run logs nothing about it. + error_patterns: [] + error_screens: [] -content: [] +content: + - name: "Bust-A-Move 2 - Arcade Edition (USA)" + catalog: redump + # The sha1 of the .cue handed to the core. + sha1: ed4a437a6f653cc71ad6ac0da68cc85eb093f298 + references: + "Beetle PSX": + recorded_from: 2026-10-27-b0150a15670d + frames: + - sha1: 7b72ebae83893b63f9fffd1685f03b1d048d9fa9 + stage: bios + shows: the Sony Computer Entertainment logo + - sha1: 0905c920a1de996664eddca94f93f75d0dcd4c52 + stage: bios + shows: the PlayStation logo licensed by Sony Computer Entertainment America + - sha1: d51ab7783f8eeafc63a28f14ce39f8e2babeffb3 + stage: game + shows: Now Loading with the yellow bubble + - sha1: 63a96bd6d1d487da1824e10d37f6658506edc451 + stage: game + shows: the Acclaim and Taito credits text, CREDIT 6 + - sha1: 6628416f377d2e25df45e5fa2126f8f9313551f0 + stage: game + shows: the Acclaim logo, CREDIT 6 + - sha1: d68892362e0f33c41cc59dac1b5a2077fe5428ee + stage: game + shows: the Taito logo on white, CREDIT 6 + - sha1: 56330c6c7646c2c261acb3f48450825cb289845a + stage: game + shows: a black screen with CREDIT 6 + "Beetle PSX HW": + recorded_from: 2026-10-27-ee69ad83c9f8 + frames: + - sha1: 7b72ebae83893b63f9fffd1685f03b1d048d9fa9 + stage: bios + shows: the Sony Computer Entertainment logo + - sha1: 0905c920a1de996664eddca94f93f75d0dcd4c52 + stage: bios + shows: the PlayStation logo licensed by Sony Computer Entertainment America + - sha1: d51ab7783f8eeafc63a28f14ce39f8e2babeffb3 + stage: game + shows: Now Loading with the yellow bubble + - sha1: 63a96bd6d1d487da1824e10d37f6658506edc451 + stage: game + shows: the Acclaim and Taito credits text, CREDIT 6 + - sha1: 6628416f377d2e25df45e5fa2126f8f9313551f0 + stage: game + shows: the Acclaim logo, CREDIT 6 + - sha1: d68892362e0f33c41cc59dac1b5a2077fe5428ee + stage: game + shows: the Taito logo on white, CREDIT 6 + - sha1: 56330c6c7646c2c261acb3f48450825cb289845a + stage: game + shows: a black screen with CREDIT 6 + "SwanStation": + recorded_from: 2026-10-27-717f780131fc + frames: + - sha1: fad859d9b8211ce9f35ad3a05b0b7d184fe14d83 + stage: bios + shows: the Sony Computer Entertainment logo + - sha1: 593a6e2600946040fefd6eb9aebdc5c0d56f0555 + stage: bios + shows: the PlayStation logo licensed by Sony Computer Entertainment America + - sha1: e5af1f2023d0d729ce7aabf52d8e03f75bb8d230 + stage: game + shows: Now Loading with the yellow bubble + - sha1: dd6dac23da6b8f4f256b8090568c52e8f8428425 + stage: game + shows: the Acclaim and Taito credits text, CREDIT 6 + - sha1: 533715dd946ba1984af1b9356e06989c7770e04a + stage: game + shows: the Acclaim logo, CREDIT 6 + - sha1: 0d17db6e9a2d5793695884c85dd2177093420fdc + stage: game + shows: the Taito logo on white, CREDIT 6 + - sha1: 2238516839dc43c0b22c00db5fe76128f5fb6f3f + stage: game + shows: a black screen with CREDIT 6 + "PCSX-ReARMed": + recorded_from: 2026-10-27-8154bab7bf80 + frames: + - sha1: e5af1f2023d0d729ce7aabf52d8e03f75bb8d230 + stage: game + shows: Now Loading with the yellow bubble + - sha1: dd6dac23da6b8f4f256b8090568c52e8f8428425 + stage: game + shows: the Acclaim and Taito credits text, CREDIT 6 + - sha1: 533715dd946ba1984af1b9356e06989c7770e04a + stage: game + shows: the Acclaim logo, CREDIT 6 + - sha1: 0d17db6e9a2d5793695884c85dd2177093420fdc + stage: game + shows: the Taito logo on white, CREDIT 6 + - sha1: 2238516839dc43c0b22c00db5fe76128f5fb6f3f + stage: game + shows: a black screen with CREDIT 6 + "PCSX1": + recorded_from: 2026-10-27-2905a9dd4b0a + frames: + - sha1: e5af1f2023d0d729ce7aabf52d8e03f75bb8d230 + stage: game + shows: Now Loading with the yellow bubble + - sha1: dd6dac23da6b8f4f256b8090568c52e8f8428425 + stage: game + shows: the Acclaim and Taito credits text, CREDIT 6 + - sha1: e10f642259f2906bb39ae07fcb4b5a36eae18287 + stage: game + shows: the Acclaim logo with a stray strip at its right edge, CREDIT 6 + - sha1: 0d17db6e9a2d5793695884c85dd2177093420fdc + stage: game + shows: the Taito logo on white, CREDIT 6 + - sha1: 2238516839dc43c0b22c00db5fe76128f5fb6f3f + stage: game + shows: a black screen with CREDIT 6 diff --git a/tests/test_core_probe.py b/tests/test_core_probe.py index bf6b00fb4..5fb9c441b 100644 --- a/tests/test_core_probe.py +++ b/tests/test_core_probe.py @@ -209,7 +209,15 @@ class OracleTests(unittest.TestCase): logs=["BIOS not found"]), self.ORACLE) self.assertEqual(verdict, "boots") self.assertEqual((evidence["rule"], evidence["frame"], evidence["stages"]), - ("reference_frame", 10, ["bios", "game"])) + ("reference_frame", 20, ["bios", "game"])) + + def test_the_bios_screens_alone_are_not_a_boot(self) -> None: + # A console that shows its logo and then refuses the disc never reached the game. + verdict, evidence = core_probe.judge( + self.rep(frames((0, self.LOGO), (10, self.BLACK), (20, self.BLACK)), uniform=[self.BLACK]), + self.ORACLE) + self.assertEqual((verdict, evidence["rule"], evidence["stages"]), ("hang", "uniform_tail", ["bios"])) + self.assertIn("no screen of the game", evidence["detail"]) def test_an_error_pattern_or_screen_without_a_reference_is_a_bios_error(self) -> None: verdict, evidence = core_probe.judge(