mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-25 13:19:03 -05:00
chore: merge the MAME required rule
This commit is contained in:
commit
14f042c540
16 files changed
+330
-33
No files matched your search
@@ -1886,7 +1886,7 @@ files:
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "upstream src/mame/seta/macs.cpp:776"
|
||||
note: "no ROM entries in the set"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/seta/macs.cpp:532-535). handle_missing_file (src/emu/romload.cpp:529-571) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
+2
-1
@@ -2402,9 +2402,10 @@ files:
|
||||
sha1: "463962ffe19880135f0d95a7beda79e27448e872"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/seta/macs.cpp:776"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/seta/macs.cpp:532-535). handle_missing_file (src/emu/romload.cpp:529-571) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
+21
-3
@@ -3,7 +3,7 @@ type: libretro
|
||||
core_classification: frozen_snapshot
|
||||
source: https://github.com/libretro/mame
|
||||
upstream: https://github.com/mamedev/mame/tree/mame0258
|
||||
profiled_date: '2026-10-17'
|
||||
profiled_date: '2026-10-22'
|
||||
source_commit: dc1a96537089d6d4ecd01d9886b21061471c70c0
|
||||
upstream_commit: 2e0aa823508663c4a27164be43467d1ef740cdcd
|
||||
core_version: '0.258'
|
||||
@@ -74,6 +74,19 @@ systems:
|
||||
- tutor
|
||||
- tandy-vis
|
||||
- trs80
|
||||
- coco
|
||||
- scv
|
||||
- apple-macintosh-ii
|
||||
- electron
|
||||
- mc10
|
||||
- pc80
|
||||
- xegs
|
||||
- dragon64
|
||||
- acorn-archimedes
|
||||
- acorn-bbc-micro
|
||||
- elektronika-bk
|
||||
- enterprise-64-128
|
||||
- vectrex
|
||||
- vgmplay
|
||||
notes: 'libretro/mame built at the 0.258 release. BIOS root sets read from mamedev/mame at mame0258: the
|
||||
sets and their ROMs are that release''s, not the current one''s.'
|
||||
@@ -107,6 +120,7 @@ files:
|
||||
- name: airlbios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10774"
|
||||
contents:
|
||||
- name: epr-21802.ic27
|
||||
@@ -1283,6 +1297,7 @@ files:
|
||||
- name: f355bios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10773"
|
||||
contents:
|
||||
- name: epr-22851.ic27
|
||||
@@ -1308,6 +1323,7 @@ files:
|
||||
- name: f355dlx.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10772"
|
||||
contents:
|
||||
- name: epr-21864.ic27
|
||||
@@ -1470,6 +1486,7 @@ files:
|
||||
- name: hod2bios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10771"
|
||||
contents:
|
||||
- name: epr-21331.ic27
|
||||
@@ -1638,6 +1655,7 @@ files:
|
||||
- name: kviper.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: konami-viper
|
||||
source_ref: "upstream src/mame/konami/viper.cpp:3424"
|
||||
contents:
|
||||
- name: 941b01.u25
|
||||
@@ -1682,7 +1700,7 @@ files:
|
||||
crc32: f78d14d7
|
||||
sha1: f129787e487984edd23bf344f2e9500c85052275
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/seta/macs.cpp:796"
|
||||
contents: []
|
||||
@@ -2339,7 +2357,7 @@ files:
|
||||
crc32: 9c436cfa
|
||||
sha1: 480ea52e74721d1963ced41be5c482b7b913ccd2
|
||||
- name: recel.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/pinball/recel.cpp:505"
|
||||
contents: []
|
||||
|
||||
+20
-2
@@ -3,7 +3,7 @@ type: libretro
|
||||
core_classification: frozen_snapshot
|
||||
source: https://github.com/libretro/mame
|
||||
upstream: https://github.com/mamedev/mame/tree/mame0278
|
||||
profiled_date: '2026-10-17'
|
||||
profiled_date: '2026-10-22'
|
||||
source_commit: fba50741006fa3e27e1897f589d2048a505b8fd6
|
||||
upstream_commit: eb05584a2b8d98d5af5587244c9cb7dcccf660fd
|
||||
core_version: '0.278'
|
||||
@@ -74,6 +74,19 @@ systems:
|
||||
- tutor
|
||||
- tandy-vis
|
||||
- trs80
|
||||
- coco
|
||||
- scv
|
||||
- apple-macintosh-ii
|
||||
- electron
|
||||
- mc10
|
||||
- pc80
|
||||
- xegs
|
||||
- dragon64
|
||||
- acorn-archimedes
|
||||
- acorn-bbc-micro
|
||||
- elektronika-bk
|
||||
- enterprise-64-128
|
||||
- vectrex
|
||||
- vgmplay
|
||||
notes: 'libretro/mame built at the 0.278 release. BIOS root sets read from mamedev/mame at mame0278: the
|
||||
sets and their ROMs are that release''s, not the current one''s.'
|
||||
@@ -107,6 +120,7 @@ files:
|
||||
- name: airlbios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10907"
|
||||
contents:
|
||||
- name: epr-21802.ic27
|
||||
@@ -1340,6 +1354,7 @@ files:
|
||||
- name: f355bios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10906"
|
||||
contents:
|
||||
- name: epr-22851.ic27
|
||||
@@ -1365,6 +1380,7 @@ files:
|
||||
- name: f355dlx.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10905"
|
||||
contents:
|
||||
- name: epr-21864.ic27
|
||||
@@ -1536,6 +1552,7 @@ files:
|
||||
- name: hod2bios.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-naomi
|
||||
source_ref: "upstream src/mame/sega/naomi.cpp:10904"
|
||||
contents:
|
||||
- name: epr-21331.ic27
|
||||
@@ -1704,6 +1721,7 @@ files:
|
||||
- name: kviper.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: konami-viper
|
||||
source_ref: "upstream src/mame/konami/viper.cpp:3258"
|
||||
contents:
|
||||
- name: 941b01.u25
|
||||
@@ -1748,7 +1766,7 @@ files:
|
||||
crc32: f78d14d7
|
||||
sha1: f129787e487984edd23bf344f2e9500c85052275
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/seta/macs.cpp:791"
|
||||
contents: []
|
||||
|
||||
@@ -325,9 +325,10 @@ files:
|
||||
source_ref: "upstream src/mame/drivers/twinkle.c:1126"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/drivers/macs.c:664"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.c:440-443). handle_missing_file (src/emu/romload.c:429-451) counts a missing NO_DUMP ROM as a warning, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -471,10 +471,11 @@ files:
|
||||
source_ref: "source src/mame/drivers/twinkle.c"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "source src/mame/drivers/macs.c:514, 740"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.c:499-502). handle_missing_file (src/emu/romload.c:430-452) counts a missing NO_DUMP ROM as a warning, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -388,10 +388,11 @@ files:
|
||||
source_ref: "upstream src/mame/drivers/suprnova.c:1734"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "upstream src/mame/drivers/macs.c:747"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.c:511-514). handle_missing_file (src/emu/romload.c:431-469) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -378,10 +378,11 @@ files:
|
||||
source_ref: "upstream src/mame/drivers/suprnova.c:1734"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "upstream src/mame/drivers/macs.c:747"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.c:511-514). handle_missing_file (src/emu/romload.c:431-469) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -350,9 +350,10 @@ files:
|
||||
source_ref: "upstream src/mame/drivers/suprnova.cpp:1785"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
source_ref: "upstream src/mame/drivers/macs.cpp:771"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.cpp:523-526). handle_missing_file (src/emu/romload.cpp:359-397) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -1559,10 +1559,11 @@ files:
|
||||
sha1: "463962ffe19880135f0d95a7beda79e27448e872"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "upstream src/mame/seta/macs.cpp:776"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/seta/macs.cpp:532-535). handle_missing_file (src/emu/romload.cpp:529-571) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -382,10 +382,11 @@ files:
|
||||
source_ref: "upstream src/mame/drivers/suprnova.c:1734"
|
||||
|
||||
- name: mac2bios.zip
|
||||
required: true
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: imax-macs
|
||||
source_ref: "upstream src/mame/drivers/macs.c:747"
|
||||
note: "macs2os_l.bin and macs2os_h.bin are both NO_DUMP (src/mame/drivers/macs.c:511-514). handle_missing_file (src/emu/romload.c:431-469) counts a missing NO_DUMP ROM as known bad, not an error, so the machine runs without the set."
|
||||
|
||||
- name: macsbios.zip
|
||||
required: true
|
||||
|
||||
@@ -40,6 +40,25 @@ def mame_ref_role(profile: dict[str, Any]) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def settled_required(entry: dict, set_data: dict) -> bool:
|
||||
"""The required flag a bios_zip entry carries after a refresh.
|
||||
|
||||
set_data["required"] is what romload.cpp does with the set missing: False
|
||||
when every ROM is NO_DUMP or ROM_OPTIONAL, so the machine runs without
|
||||
it, and nothing outranks that. True only says the machine itself stops;
|
||||
whether the core needs that machine is the profile's call, so a curated
|
||||
false is kept. The exception is a false over no contents, which is
|
||||
what an undumped set leaves: once a ROM is dumped, the set is required.
|
||||
"""
|
||||
current = entry.get("required", True)
|
||||
code = set_data.get("required")
|
||||
if code is False:
|
||||
return False
|
||||
if code is True and current is False and not entry.get("contents"):
|
||||
return True
|
||||
return current
|
||||
|
||||
|
||||
def merge_mame_profile(
|
||||
profile_path: str,
|
||||
hashes_path: str,
|
||||
@@ -48,11 +67,11 @@ def merge_mame_profile(
|
||||
) -> dict[str, Any]:
|
||||
"""Merge MAME bios_zip entries from upstream hash data.
|
||||
|
||||
Preserves system, note, required per entry. Updates contents and
|
||||
source_ref from the hashes JSON. New sets are only added when
|
||||
add_new=True (main profile). Entries not in the hash data are
|
||||
left untouched (the scraper only covers MACHINE_IS_BIOS_ROOT sets,
|
||||
not all machine ROM sets).
|
||||
Preserves system and note per entry. Updates contents and source_ref
|
||||
from the hashes JSON, and required where the source settles it (see
|
||||
settled_required). New sets are only added when add_new=True (main
|
||||
profile). Entries not in the hash data are left untouched (the scraper
|
||||
only covers MACHINE_IS_BIOS_ROOT sets, not all machine ROM sets).
|
||||
|
||||
If write=True, backs up existing profile to .old.yml before writing.
|
||||
"""
|
||||
@@ -93,13 +112,14 @@ def merge_mame_profile(
|
||||
entry["contents"] = contents
|
||||
if source_ref:
|
||||
entry["source_ref"] = source_ref
|
||||
entry["required"] = settled_required(existing_by_name[set_name], set_data)
|
||||
updated_bios.append(entry)
|
||||
matched_names.add(set_name)
|
||||
elif add_new:
|
||||
# New BIOS set, only added to the main profile
|
||||
entry = {
|
||||
"name": f"{set_name}.zip",
|
||||
"required": True,
|
||||
"required": settled_required({}, set_data),
|
||||
"category": "bios_zip",
|
||||
"system": None,
|
||||
"source_ref": source_ref,
|
||||
@@ -245,7 +265,9 @@ def _diff_mame(
|
||||
# rots, which is exactly what profile_sync then reports as drift.
|
||||
ref_moved = bool(new_ref) and old_entry.get("source_ref") != new_ref
|
||||
|
||||
if _contents_differ(old_contents, new_contents) or ref_moved:
|
||||
required_moved = old_entry.get("required", True) != settled_required(old_entry, set_data)
|
||||
|
||||
if _contents_differ(old_contents, new_contents) or ref_moved or required_moved:
|
||||
updated.append(set_name)
|
||||
else:
|
||||
unchanged += 1
|
||||
@@ -435,7 +457,7 @@ def _patch_scalar(text: str, key: str, value: str) -> str:
|
||||
|
||||
|
||||
def _patch_bios_entries(text: str, files: list[dict]) -> str:
|
||||
"""Patch contents and source_ref for existing bios_zip entries in-place.
|
||||
"""Patch contents, source_ref and required of bios_zip entries in-place.
|
||||
|
||||
Processes entries in reverse order to preserve line offsets.
|
||||
Each entry's "owned" lines are: the `- name:` line plus all indented
|
||||
@@ -499,6 +521,13 @@ def _patch_bios_entries(text: str, files: list[dict]) -> str:
|
||||
lines.insert(last_owned + 1, f' source_ref: "{source_ref}"')
|
||||
last_owned += 1
|
||||
|
||||
# The source settles required for a set the machine runs without
|
||||
if "required" in fe:
|
||||
for j in range(start_line + 1, last_owned + 1):
|
||||
if re.match(r"^ required:", lines[j]):
|
||||
lines[j] = f" required: {str(fe['required']).lower()}"
|
||||
break
|
||||
|
||||
# Remove existing contents block if present
|
||||
contents_start = None
|
||||
contents_end = None
|
||||
|
||||
@@ -11,6 +11,7 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -41,6 +42,7 @@ from ._hash_merge import (
|
||||
merge_mame_devices,
|
||||
merge_mame_profile,
|
||||
merge_mame_support,
|
||||
settled_required,
|
||||
)
|
||||
from .mame_devices import (
|
||||
attribute_softlists,
|
||||
@@ -241,12 +243,18 @@ def _find_mame_profiles() -> list[Path]:
|
||||
# declare mamedev/mame upstream but build from their own fork at
|
||||
# another release: refreshing their refs from current MAME moves
|
||||
# them onto paths their tree does not have, such as the 0.289 move
|
||||
# of neogeo.cpp from src/mame/neogeo/ to src/mame/snk/.
|
||||
# of neogeo.cpp from src/mame/neogeo/ to src/mame/snk/. A profile
|
||||
# that builds mamedev/mame itself at a pinned commit, as pSxMAME
|
||||
# does at 0.133, is a snapshot of that tree just the same.
|
||||
if (
|
||||
isinstance(upstream, str)
|
||||
and upstream.rstrip("/") == "https://github.com/mamedev/mame"
|
||||
and isinstance(source, str)
|
||||
and source.rstrip("/") in _MAME_TREES
|
||||
and not (
|
||||
source.rstrip("/") == "https://github.com/mamedev/mame"
|
||||
and data.get("source_commit")
|
||||
)
|
||||
):
|
||||
profiles.append(path)
|
||||
except (yaml.YAMLError, OSError) as exc:
|
||||
@@ -427,7 +435,8 @@ def release_profile(
|
||||
BIOS root sets and their ROMs change between releases, so the current
|
||||
MAME profile does not describe them. Each set keeps the system and the
|
||||
required flag the current profile gives it, while the contents and the line
|
||||
are the release's own.
|
||||
are the release's own, and so is a set the release runs without: recel is
|
||||
undumped at 0.258 and dumped later.
|
||||
"""
|
||||
version = release.removeprefix("mame")
|
||||
version = f"{version[0]}.{version[1:]}" if version.isdigit() else version
|
||||
@@ -440,7 +449,7 @@ def release_profile(
|
||||
name = f"{set_name}.zip"
|
||||
entry: dict[str, Any] = {
|
||||
"name": name,
|
||||
"required": known.get(name, {}).get("required", True),
|
||||
"required": settled_required(known.get(name, {}), data),
|
||||
"category": "bios_zip",
|
||||
}
|
||||
if known.get(name, {}).get("system"):
|
||||
@@ -471,6 +480,9 @@ def release_profile(
|
||||
}
|
||||
|
||||
|
||||
_QUOTE_REF = re.compile(r'^(\s*source_ref: )([^"\'\n].*)$', re.MULTILINE)
|
||||
|
||||
|
||||
def _write_release(args: argparse.Namespace) -> None:
|
||||
"""Write the profile of one MAME release, read from its own tag."""
|
||||
try:
|
||||
@@ -487,6 +499,9 @@ def _write_release(args: argparse.Namespace) -> None:
|
||||
args.built_by,
|
||||
)
|
||||
text = yaml.safe_dump(profile, sort_keys=False, allow_unicode=True, width=100)
|
||||
# Citations are written double-quoted in every profile: left bare, each
|
||||
# regeneration rewrote all of them.
|
||||
text = _QUOTE_REF.sub(r'\g<1>"\g<2>"', text)
|
||||
write_text_atomic(str(args.profile), text)
|
||||
print(f"{args.profile}: {len(profile['files'])} BIOS root sets at {args.release}")
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
Extracts BIOS root sets and ROM definitions from MAME driver sources.
|
||||
Handles GAME/GAMEL/SYST/COMP/CONS macros with MACHINE_IS_BIOS_ROOT flag,
|
||||
ROM_START/ROM_END blocks, ROM_LOAD variants, ROM_REGION, ROM_SYSTEM_BIOS,
|
||||
NO_DUMP filtering, and BAD_DUMP flagging.
|
||||
NO_DUMP filtering, BAD_DUMP and ROM_OPTIONAL flagging, and whether a missing
|
||||
set stops the machine.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -66,6 +67,8 @@ _CRC_SHA = re.compile(
|
||||
_NO_DUMP = re.compile(r"\bNO_DUMP\b")
|
||||
_BAD_DUMP = re.compile(r"\bBAD_DUMP\b")
|
||||
_ROM_BIOS = re.compile(r"ROM_BIOS\s*\(\s*(\d+)\s*\)")
|
||||
# ROM_LOAD_OPTIONAL expands to ROMX_LOAD(..., ROM_OPTIONAL) (src/emu/romentry.h)
|
||||
_OPTIONAL = re.compile(r"\bROM_OPTIONAL\b|\bROMX?_LOAD\w*_OPTIONAL\b")
|
||||
|
||||
|
||||
def strip_comments(source: str) -> str:
|
||||
@@ -161,12 +164,15 @@ def find_bios_root_sets(source: str, filename: str) -> dict[str, dict]:
|
||||
return results
|
||||
|
||||
|
||||
def parse_rom_block(source: str, set_name: str) -> list[dict]:
|
||||
def parse_rom_block(
|
||||
source: str, set_name: str, keep_no_dump: bool = False,
|
||||
) -> list[dict]:
|
||||
"""Parse ROM definitions for a given set name.
|
||||
|
||||
Finds the ROM_START(set_name)...ROM_END block, expands local
|
||||
#define macros that contain ROM_LOAD/ROM_REGION calls, then
|
||||
extracts all ROM entries. Skips NO_DUMP, flags BAD_DUMP.
|
||||
extracts all ROM entries. Skips NO_DUMP unless keep_no_dump, which
|
||||
returns them flagged no_dump. Flags BAD_DUMP and ROM_OPTIONAL.
|
||||
"""
|
||||
pattern = re.compile(
|
||||
r"ROM_START\s*\(\s*" + re.escape(set_name) + r"\s*\)",
|
||||
@@ -187,7 +193,22 @@ def parse_rom_block(source: str, set_name: str) -> list[dict]:
|
||||
macros = _collect_rom_macros(source)
|
||||
block = _expand_macros(block, macros, depth=5)
|
||||
|
||||
return _parse_rom_entries(block)
|
||||
return _parse_rom_entries(block, keep_no_dump)
|
||||
|
||||
|
||||
def set_is_required(entries: list[dict]) -> bool | None:
|
||||
"""Whether MAME refuses to run the machine when the set is missing.
|
||||
|
||||
handle_missing_file (src/emu/romload.cpp) counts a missing ROM_OPTIONAL
|
||||
as a warning and a missing NO_DUMP as known bad. Any other ROM raises
|
||||
an error, and display_rom_load_results throws
|
||||
EMU_ERR_MISSING_FILES on errors. A set whose every ROM is optional or
|
||||
undumped warns and the machine runs. None when the block holds no
|
||||
ROM_LOAD at all: nothing was read, so nothing is decided.
|
||||
"""
|
||||
if not entries:
|
||||
return None
|
||||
return any(not e.get("no_dump") and not e.get("optional") for e in entries)
|
||||
|
||||
|
||||
def parse_mame_source_tree(base_path: str) -> dict[str, dict]:
|
||||
@@ -213,12 +234,15 @@ def parse_mame_source_tree(base_path: str) -> dict[str, dict]:
|
||||
|
||||
bios_sets = find_bios_root_sets(content, rel_path)
|
||||
for set_name, info in bios_sets.items():
|
||||
roms = parse_rom_block(content, set_name)
|
||||
entries = parse_rom_block(content, set_name, keep_no_dump=True)
|
||||
results[set_name] = {
|
||||
"source_file": info["source_file"],
|
||||
"source_line": info["source_line"],
|
||||
"roms": roms,
|
||||
"roms": [e for e in entries if not e.get("no_dump")],
|
||||
}
|
||||
required = set_is_required(entries)
|
||||
if required is not None:
|
||||
results[set_name]["required"] = required
|
||||
|
||||
return results
|
||||
|
||||
@@ -353,7 +377,7 @@ def _split_macro_args(inner: str) -> list[str]:
|
||||
return args
|
||||
|
||||
|
||||
def _parse_rom_entries(block: str) -> list[dict]:
|
||||
def _parse_rom_entries(block: str, keep_no_dump: bool = False) -> list[dict]:
|
||||
"""Parse ROM entries from a ROM block (content between ROM_START and ROM_END).
|
||||
|
||||
Uses regex scanning over the entire block (not line-by-line) to handle
|
||||
@@ -398,7 +422,8 @@ def _parse_rom_entries(block: str) -> list[dict]:
|
||||
context_end = m.end() + 200
|
||||
context = block[context_start : min(context_end, len(block))]
|
||||
|
||||
if _NO_DUMP.search(context):
|
||||
no_dump = bool(_NO_DUMP.search(context))
|
||||
if no_dump and not keep_no_dump:
|
||||
continue
|
||||
|
||||
rom_name = m.group(1)
|
||||
@@ -435,6 +460,10 @@ def _parse_rom_entries(block: str) -> list[dict]:
|
||||
entry["bios_index"] = bios_index
|
||||
entry["bios_label"] = bios_label
|
||||
entry["bios_description"] = bios_description
|
||||
if _OPTIONAL.search(context):
|
||||
entry["optional"] = True
|
||||
if no_dump:
|
||||
entry["no_dump"] = True
|
||||
|
||||
roms.append(entry)
|
||||
|
||||
|
||||
@@ -170,6 +170,85 @@ class TestMameMerge(unittest.TestCase):
|
||||
self.assertEqual(entry["system"], "snk-neogeo-mvs")
|
||||
self.assertFalse(entry["required"])
|
||||
|
||||
def test_merge_sets_required_false_for_a_set_the_machine_runs_without(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"].append({
|
||||
"name": "mac2bios.zip", "required": True, "category": "bios_zip",
|
||||
"note": "kept",
|
||||
})
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["mac2bios"] = {
|
||||
"source_file": "src/mame/seta/macs.cpp", "source_line": 776,
|
||||
"roms": [], "required": False,
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
|
||||
diff = compute_diff(profile_path, hashes_path, mode="mame")
|
||||
self.assertIn("mac2bios", diff["updated"])
|
||||
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "mac2bios.zip")
|
||||
self.assertFalse(entry["required"])
|
||||
self.assertEqual(entry["note"], "kept")
|
||||
|
||||
def test_written_profile_carries_the_settled_required(self) -> None:
|
||||
"""The text patcher rewrote contents and source_ref but left required."""
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"] = {"mac2bios": {
|
||||
"source_file": "src/mame/seta/macs.cpp", "source_line": 776,
|
||||
"roms": [], "required": False,
|
||||
}}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = str(p / "mame.yml")
|
||||
Path(profile_path).write_text(
|
||||
'emulator: MAME\ncore_version: "0.289"\nfiles:\n'
|
||||
" - name: mac2bios.zip\n required: true\n category: bios_zip\n"
|
||||
' source_ref: "upstream src/mame/seta/macs.cpp:776"\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
merge_mame_profile(profile_path, hashes_path, write=True)
|
||||
written = yaml.safe_load(Path(profile_path).read_text(encoding="utf-8"))
|
||||
entry = next(f for f in written["files"] if f["name"] == "mac2bios.zip")
|
||||
self.assertIs(entry["required"], False)
|
||||
|
||||
def test_merge_keeps_a_curated_false_over_a_fatal_set(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"][0]["required"] = False
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["neogeo"]["required"] = True
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "neogeo.zip")
|
||||
self.assertFalse(entry["required"])
|
||||
|
||||
def test_merge_restores_required_once_an_undumped_set_is_dumped(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"].append({
|
||||
"name": "recel.zip", "required": False, "category": "bios_zip",
|
||||
"contents": [],
|
||||
})
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["recel"] = {
|
||||
"source_file": "src/mame/pinball/recel.cpp", "source_line": 546,
|
||||
"roms": [{"name": "a2361.b1", "size": 1024, "crc32": "eeb8f3f0"}],
|
||||
"required": True,
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "recel.zip")
|
||||
self.assertTrue(entry["required"])
|
||||
|
||||
def test_merge_adds_new_bios_set(self) -> None:
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["pgm"] = {
|
||||
@@ -405,6 +484,30 @@ class AReleaseProfileDescribesItsOwnRelease(unittest.TestCase):
|
||||
self.assertNotIn("system", files["newset.zip"])
|
||||
self.assertEqual(files["neogeo.zip"]["source_ref"], "upstream src/mame/neogeo/neogeo.cpp:10")
|
||||
|
||||
def test_a_set_the_release_runs_without_is_not_required(self):
|
||||
"""recel is undumped at 0.258: the current profile's true does not apply."""
|
||||
from scripts.scraper.mame_hash_scraper import release_profile
|
||||
|
||||
bios_sets = {
|
||||
"recel": {"source_file": "src/mame/pinball/recel.cpp", "source_line": 505,
|
||||
"roms": [], "required": False},
|
||||
"neogeo": {"source_file": "src/mame/neogeo/neogeo.cpp", "source_line": 10,
|
||||
"roms": [{"name": "sp-s2.sp1", "size": 131072, "crc32": "9036d879"}],
|
||||
"required": True},
|
||||
}
|
||||
reference = {"files": [
|
||||
{"name": "recel.zip", "category": "bios_zip", "required": True,
|
||||
"contents": [{"name": "a2361.b1", "size": 1024, "crc32": "eeb8f3f0"}]},
|
||||
{"name": "neogeo.zip", "category": "bios_zip", "required": True},
|
||||
]}
|
||||
profile = release_profile(
|
||||
"mame0258", bios_sets, "a" * 40, "b" * 40, ["mame0258"], reference,
|
||||
["recalbox"],
|
||||
)
|
||||
files = {f["name"]: f for f in profile["files"]}
|
||||
self.assertFalse(files["recel.zip"]["required"])
|
||||
self.assertTrue(files["neogeo.zip"]["required"])
|
||||
|
||||
def test_a_release_profile_is_left_out_of_the_current_refresh(self):
|
||||
from scripts.scraper.mame_hash_scraper import _find_mame_profiles
|
||||
|
||||
@@ -412,6 +515,12 @@ class AReleaseProfileDescribesItsOwnRelease(unittest.TestCase):
|
||||
self.assertIn("mame.yml", names)
|
||||
self.assertFalse({"mame0258.yml", "mame0278.yml"} & names)
|
||||
|
||||
def test_a_pinned_build_of_the_mame_tree_is_left_out(self):
|
||||
"""pSxMAME builds mamedev/mame at 0.133: refreshed, it would carry 0.289 refs."""
|
||||
from scripts.scraper.mame_hash_scraper import _find_mame_profiles
|
||||
|
||||
self.assertNotIn("psxmame.yml", {path.name for path in _find_mame_profiles()})
|
||||
|
||||
|
||||
class TestFbneoMerge(unittest.TestCase):
|
||||
"""Tests for merge_fbneo_profile."""
|
||||
|
||||
@@ -10,6 +10,7 @@ from scripts.scraper.mame_parser import (
|
||||
find_bios_root_sets,
|
||||
parse_mame_source_tree,
|
||||
parse_rom_block,
|
||||
set_is_required,
|
||||
)
|
||||
|
||||
# Standard GAME macro with MACHINE_IS_BIOS_ROOT, multiple ROM entries, BIOS variants
|
||||
@@ -51,6 +52,35 @@ ROM_END
|
||||
GAME( 2000, testnd, 0, testnd, testnd, test_state, init_test, ROT0, "Test", "Test ND", MACHINE_IS_BIOS_ROOT )
|
||||
"""
|
||||
|
||||
# Every ROM undumped, as macs.cpp declares mac2bios: the machine runs without the set
|
||||
ALL_NODUMP_FIXTURE = """\
|
||||
#define MACS2_BIOS \\
|
||||
ROM_REGION( 0x400000, "bios", 0 ) \\
|
||||
ROM_LOAD16_BYTE( "macs2os_l.bin", 0x00000, 0x80000, NO_DUMP ) \\
|
||||
ROM_LOAD16_BYTE( "macs2os_h.bin", 0x00001, 0x80000, NO_DUMP )
|
||||
|
||||
ROM_START( mac2bios )
|
||||
MACS2_BIOS
|
||||
|
||||
ROM_REGION( 0x1000000, "maincpu", 0 )
|
||||
ROM_COPY( "bios", 0x000000, 0x000000, 0x400000 )
|
||||
ROM_END
|
||||
|
||||
GAME( 1995, mac2bios, 0, macs, macs_m, macs_state, init_macs2, ROT0, "I'Max", "Multi Amenity Cassette System 2 BIOS", MACHINE_IS_BIOS_ROOT | MACHINE_NOT_WORKING )
|
||||
"""
|
||||
|
||||
# Every ROM optional, through both spellings romentry.h offers, plus one undumped
|
||||
ALL_OPTIONAL_FIXTURE = """\
|
||||
ROM_START( testopt )
|
||||
ROM_REGION( 0x10000, "maincpu", 0 )
|
||||
ROM_LOAD_OPTIONAL( "opt1.rom", 0x00000, 0x4000, CRC(aabbccdd) SHA1(1122334455667788990011223344556677889900) )
|
||||
ROMX_LOAD( "opt2.rom", 0x04000, 0x4000, CRC(aabbccde) SHA1(1122334455667788990011223344556677889901), ROM_OPTIONAL )
|
||||
ROM_LOAD( "gone.rom", 0x08000, 0x4000, NO_DUMP )
|
||||
ROM_END
|
||||
|
||||
GAME( 2000, testopt, 0, testopt, testopt, test_state, init_test, ROT0, "Test", "Test Optional", MACHINE_IS_BIOS_ROOT )
|
||||
"""
|
||||
|
||||
# ROM_LOAD with BAD_DUMP
|
||||
BADDUMP_FIXTURE = """\
|
||||
ROM_START( testbd )
|
||||
@@ -284,6 +314,47 @@ ROM_END
|
||||
self.assertEqual(roms[0]["sha1"], "aabbccddeeff00112233aabbccddeeff00112233")
|
||||
|
||||
|
||||
class TestSetIsRequired(unittest.TestCase):
|
||||
"""A set is required only if romload.cpp errors when it is missing."""
|
||||
|
||||
def test_all_no_dump_set_is_not_required(self) -> None:
|
||||
entries = parse_rom_block(ALL_NODUMP_FIXTURE, "mac2bios", keep_no_dump=True)
|
||||
self.assertEqual([e["name"] for e in entries], ["macs2os_l.bin", "macs2os_h.bin"])
|
||||
self.assertTrue(all(e["no_dump"] for e in entries))
|
||||
self.assertIs(set_is_required(entries), False)
|
||||
|
||||
def test_optional_and_no_dump_set_is_not_required(self) -> None:
|
||||
entries = parse_rom_block(ALL_OPTIONAL_FIXTURE, "testopt", keep_no_dump=True)
|
||||
self.assertEqual(len(entries), 3)
|
||||
self.assertTrue(entries[0]["optional"] and entries[1]["optional"])
|
||||
self.assertIs(set_is_required(entries), False)
|
||||
|
||||
def test_one_dumped_rom_makes_the_set_required(self) -> None:
|
||||
entries = parse_rom_block(NODUMP_FIXTURE, "testnd", keep_no_dump=True)
|
||||
self.assertIs(set_is_required(entries), True)
|
||||
|
||||
def test_bad_dump_is_still_fatal(self) -> None:
|
||||
entries = parse_rom_block(BADDUMP_FIXTURE, "testbd", keep_no_dump=True)
|
||||
self.assertIs(set_is_required(entries), True)
|
||||
|
||||
def test_no_rom_read_decides_nothing(self) -> None:
|
||||
self.assertIsNone(set_is_required([]))
|
||||
|
||||
def test_no_dump_stays_out_of_the_default_parse(self) -> None:
|
||||
self.assertEqual(parse_rom_block(ALL_NODUMP_FIXTURE, "mac2bios"), [])
|
||||
|
||||
def test_tree_records_required_per_set(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
mame_dir = os.path.join(tmpdir, "src", "mame", "seta")
|
||||
os.makedirs(mame_dir)
|
||||
with open(os.path.join(mame_dir, "macs.cpp"), "w") as f:
|
||||
f.write(ALL_NODUMP_FIXTURE + NEOGEO_FIXTURE)
|
||||
results = parse_mame_source_tree(tmpdir)
|
||||
self.assertIs(results["mac2bios"]["required"], False)
|
||||
self.assertEqual(results["mac2bios"]["roms"], [])
|
||||
self.assertIs(results["neogeo"]["required"], True)
|
||||
|
||||
|
||||
class TestParseMameSourceTree(unittest.TestCase):
|
||||
"""Tests for parse_mame_source_tree."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user