From 4e8d3750741abe28df37ce4f81dbcb833af5cce1 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Wed, 21 Oct 2026 05:20:00 +0200 Subject: [PATCH] fix: serve australian mega cd discs their pal bios BlastEm and Kega Fusion pick the European Mega CD BIOS for every disc whose region code is the PAL one, Australian discs included: BlastEm reads E or bit 8 of the header region (romdb.c:176-215), Fusion the security byte 0x64 at 0x20B. Both now carry oceania, and a repo-wide test holds every European Mega CD BIOS to it. Fusion picks its export Master System BIOS from the CountryOrder setting or a CRC32 list, never from the cart, so bios_U.sms and bios_E.sms carry no region. --- emulators/blastem.yml | 4 ++-- emulators/kega-fusion.yml | 16 +++++++--------- tests/test_region.py | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/emulators/blastem.yml b/emulators/blastem.yml index 9487baf7..10a0f005 100644 --- a/emulators/blastem.yml +++ b/emulators/blastem.yml @@ -80,10 +80,10 @@ files: - name: bios_CD_E.bin system: sega-megacd - region: [europe] + region: [europe, oceania] required: true mode: libretro - note: "Mega CD BIOS for discs whose region resolves to E (segacd.c:1587-1588). Same load rules as bios_CD_U.bin." + note: "Mega CD BIOS for discs whose region resolves to E (segacd.c:1587-1588). The header code E, or bit 8 of a hex code, is the only PAL value the code reads, so Australian discs take this branch too (romdb.c:176-215). Same load rules as bios_CD_U.bin." source_ref: "source libblastem.c:502, source segacd.c:1573-1615" - name: bios_CD_J.bin diff --git a/emulators/kega-fusion.yml b/emulators/kega-fusion.yml index a2c60d45..b24f4358 100644 --- a/emulators/kega-fusion.yml +++ b/emulators/kega-fusion.yml @@ -71,11 +71,11 @@ files: - name: eu_mcd1_9210.bin aliases: [bios_CD_E.bin] system: sega-megacd - region: [europe] + region: [europe, oceania] required: true description: "Mega CD (Europe) boot ROM" - note: "Opened from SCDEURBIOS for the European region, same 128 KB read and same lock when it is missing, with the EUR message." - source_ref: "Fusion.exe 0x44b68a (default path), 0x478979-0x4789d6 (open, message, fread 0x20000)" + note: "Opened from SCDEURBIOS for the European region, same 128 KB read and same lock when it is missing, with the EUR message. With country autodetect on (the default), the disc's security byte at 0x20B picks the region: 0x7A USA, 0xA1 JAP, 0x64 EUR. EUR is the only branch that sets the PAL version bits (0xC0) and 50 Hz, so Australian discs take it too." + source_ref: "Fusion.exe 0x44b68a (default path), 0x478979-0x4789d6 (open, message, fread 0x20000), 0x44756b-0x44758a and 0x44cfc0-0x44cfe3 (security byte), 0x478963-0x478970 (PAL branch)" - name: 32X_G_BIOS.bin system: sega-32x @@ -110,11 +110,10 @@ files: - name: bios_U.sms system: sega-mastersystem - region: [north-america] required: false description: "Master System (USA) boot ROM" - note: "Read from SMSUSABIOS, up to 512 KB, for the USA region unless SMSBIOSDisable is set. A missing file leaves the cartridge to start directly. No file name is fixed by the code." - source_ref: "Fusion.exe 0x47d541-0x47d5b9" + note: "Read from SMSUSABIOS, up to 512 KB, for the USA region unless SMSBIOSDisable is set. A missing file leaves the cartridge to start directly. No file name is fixed by the code. The header nibble at 0x7FFF tells Japan from export only: an export cart gets USA or EUR from the CountryOrder setting (USA by default), or from a CRC32 list held in the executable." + source_ref: "Fusion.exe 0x47d541-0x47d5b9, 0x45c173-0x45c1f4 (header nibble, CountryOrder), 0x47ce20-0x47ced1 (CRC32 list)" - name: bios_J.sms system: sega-mastersystem @@ -126,11 +125,10 @@ files: - name: bios_E.sms system: sega-mastersystem - region: [europe] required: false description: "Master System (Europe) boot ROM" - note: "Read from SMSEURBIOS for the European region, same rules as the USA image." - source_ref: "Fusion.exe 0x47d60c-0x47d659" + note: "Read from SMSEURBIOS for the European region, same rules as the USA image. EUR comes from the CountryOrder setting or the CRC32 list, never from the header." + source_ref: "Fusion.exe 0x47d60c-0x47d659, 0x45c1a4-0x45c1f4 (CountryOrder), 0x47cea1-0x47ced1 (CRC32 list)" - name: bios.gg system: sega-gamegear diff --git a/tests/test_region.py b/tests/test_region.py index cf0771ff..9ed35589 100644 --- a/tests/test_region.py +++ b/tests/test_region.py @@ -889,6 +889,8 @@ class RegionalRequestsKeepWhatTheCodeLoads(unittest.TestCase): ("ace-dl", ["france"], "private/firmware/Amstrad_s4.cpr"), ("duckstation", ["brazil"], "scph5501.bin"), ("duckstation", ["south-korea"], "scph5500.bin"), + ("blastem", ["australia", "north-america"], "bios_CD_E.bin"), + ("kega-fusion", ["australia", "north-america"], "eu_mcd1_9210.bin"), ) def test_each_request_keeps_its_file(self): @@ -1094,6 +1096,42 @@ class MegaCdAmericasIsOneCode(unittest.TestCase): self.assertEqual(narrow, []) +class MegaCdEuropeServesOceania(unittest.TestCase): + """A Mega CD disc carries one PAL code for Europe and Australia, so every + emulator picking the European BIOS by that code picks it for an + Australian disc too. blastem and kega-fusion tagged it europe alone, and a + --region au,us pack dropped the BIOS those discs boot with.""" + + def test_a_european_mega_cd_bios_includes_oceania(self): + import yaml + + root = Path(__file__).resolve().parents[1] + narrow = [] + for path in sorted((root / "emulators").glob("*.yml")): + profile = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + for entry in profile.get("files") or []: + system = str(entry.get("system", "")) + regions = entry.get("region") or [] + if system in ("sega-megacd", "mega-cd") and "europe" in regions \ + and "oceania" not in regions: + narrow.append(f"{path.stem}: {entry.get('name')}") + self.assertEqual(narrow, []) + + +class FusionSmsExportBiosFollowsTheSetting(unittest.TestCase): + """Kega Fusion tells a Japanese Master System cart from an export one by + the header, then picks USA or EUR from its CountryOrder setting or a CRC32 + list. Neither export BIOS is chosen for a territory the cart names.""" + + def test_the_export_bioses_are_unregioned(self): + from common import load_emulator_profiles + + files = {f["name"]: f for f in load_emulator_profiles("emulators")["kega-fusion"]["files"]} + for name in ("bios_U.sms", "bios_E.sms"): + with self.subTest(name=name): + self.assertNotIn("region", files[name]) + + class NoMarketStopsAtAustralia(unittest.TestCase): """simple64 tagged its PAL PIF [europe, australia]. New Zealand is not under australia, so --region new-zealand kept only the NTSC PIF, though