From 1a1f19be2da1e634e521f1a1515c0f6923b55078 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:48:24 +0200 Subject: [PATCH] feat: check a MAME ref against the set it names profile_sync follows content, so a ref that drifted still anchors where the cited text went. That is drift detection working, and it cannot answer the only question a MAME romset ref asks: does this line declare this set. It flagged five refs in one driver file where nineteen were stale, the fourteen others having been relocatable somewhere plausible. mame_ref_audit asks the stronger question and found ninety-two across the four profiles whose upstream still moves: mame 66, mamearcade 18, mamemess 6, groovymame 2. Each had exactly one declaration to point at. The frozen generations, mame2009 through mame2016, come out clean, which is the check saying it finds drift only where drift can happen. The set name is argument 1 of the machine macro. Matching it anywhere on the line matches every clone naming it as parent, which is most of a driver, and comments are stripped first because a declaration can sit behind one. A set no machine declares is reported as not judgeable, not wrong: device archives take their DEFINE_DEVICE_TYPE shortname. --- emulators/groovymame.yml | 4 +- emulators/mame.yml | 132 ++++++++++++++++---------------- emulators/mamearcade.yml | 36 ++++----- emulators/mamemess.yml | 12 +-- scripts/mame_ref_audit.py | 144 +++++++++++++++++++++++++++++++++++ tests/test_mame_ref_audit.py | 127 ++++++++++++++++++++++++++++++ wiki/tools.md | 28 +++++++ 7 files changed, 391 insertions(+), 92 deletions(-) create mode 100644 scripts/mame_ref_audit.py create mode 100644 tests/test_mame_ref_audit.py diff --git a/emulators/groovymame.yml b/emulators/groovymame.yml index dbae6751..098f23d5 100644 --- a/emulators/groovymame.yml +++ b/emulators/groovymame.yml @@ -1499,7 +1499,7 @@ files: required: true category: bios_zip system: konami-twinkle - source_ref: "src/mame/konami/twinkle.cpp:1360" + source_ref: "src/mame/konami/twinkle.cpp:1655" contents: - name: 863a03.7b size: 524288 @@ -2121,7 +2121,7 @@ files: - name: aristmk5.zip required: true category: bios_zip - source_ref: "src/mame/acorn/aristmk5.cpp:2631" + source_ref: "src/mame/acorn/aristmk5.cpp:9293" contents: - name: setchip v4.04.09.u7 size: 524288 diff --git a/emulators/mame.yml b/emulators/mame.yml index 6db494f1..35075767 100644 --- a/emulators/mame.yml +++ b/emulators/mame.yml @@ -269,7 +269,7 @@ files: required: true category: bios_zip system: igs-pgm - source_ref: "src/mame/igs/pgm.cpp:5548" + source_ref: "src/mame/igs/pgm.cpp:5519" contents: - name: pgm_p02s.u20 size: 131072 @@ -552,7 +552,7 @@ files: required: true category: bios_zip system: sammy-atomiswave - source_ref: "src/mame/sega/dc_atomiswave.cpp:1519" + source_ref: "src/mame/sega/dc_atomiswave.cpp:1480" contents: - name: bios0.ic23 size: 131072 @@ -689,7 +689,7 @@ files: required: true category: bios_zip system: sega-stv - source_ref: "src/mame/sega/stv.cpp:4067" + source_ref: "src/mame/sega/stv.cpp:3949" contents: - name: epr-23603.ic8 size: 524288 @@ -907,7 +907,7 @@ files: required: true category: bios_zip system: sega-triforce - source_ref: "src/mame/sega/triforce.cpp:1310" + source_ref: "src/mame/sega/triforce.cpp:1304" contents: - name: triforce_bootrom.bin size: 2097152 @@ -917,7 +917,7 @@ files: - name: shtzone.zip required: true category: bios_zip - source_ref: "src/mame/sega/shtzone.cpp:376" + source_ref: "src/mame/sega/shtzone.cpp:378" contents: - name: epr10894a.20 size: 16384 @@ -927,7 +927,7 @@ files: - name: sammymdl.zip required: true category: bios_zip - source_ref: "src/mame/sigma/sammymdl.cpp:1025" + source_ref: "src/mame/sigma/sammymdl.cpp:1027" contents: - name: vm1211l01.u2 description: IPL Ver. 5.0 @@ -950,7 +950,7 @@ files: required: true category: bios_zip system: sega-megaplay - source_ref: "src/mame/sega/megaplay.cpp:1018" + source_ref: "src/mame/sega/megaplay.cpp:1016" contents: - name: ep15294.ic2 size: 131072 @@ -990,7 +990,7 @@ files: required: true category: bios_zip system: sega-megatech - source_ref: "src/mame/sega/megatech.cpp:1430" + source_ref: "src/mame/sega/megatech.cpp:1442" contents: - name: epr-12664.20 description: Ver 1 @@ -1226,7 +1226,7 @@ files: required: true category: bios_zip system: nintendo-playch10 - source_ref: "src/mame/nintendo/playch10.cpp:2981" + source_ref: "src/mame/nintendo/playch10.cpp:2982" contents: - name: pch1-c__8t_e-2.8t size: 16384 @@ -1402,7 +1402,7 @@ files: required: true category: bios_zip system: commodore-cubo - source_ref: "src/mame/amiga/cubo.cpp:1435" + source_ref: "src/mame/amiga/cubo.cpp:1433" contents: - name: 391640-03.u6a size: 1048576 @@ -1436,7 +1436,7 @@ files: required: true category: bios_zip system: namco-system573 - source_ref: "src/mame/konami/ksys573.cpp:6541" + source_ref: "src/mame/konami/ksys573.cpp:6289" contents: - name: 700a01.22g description: Standard @@ -1473,7 +1473,7 @@ files: - name: konamigx.zip required: true category: bios_zip - source_ref: "src/mame/konami/konamigx.cpp:4191" + source_ref: "src/mame/konami/konamigx.cpp:4193" contents: - name: 300a01.34k size: 131072 @@ -1484,7 +1484,7 @@ files: required: true category: bios_zip system: konami-gv - source_ref: "src/mame/konami/konamigv.cpp:1450" + source_ref: "src/mame/konami/konamigv.cpp:1444" contents: - name: 999a01.7e size: 524288 @@ -1494,7 +1494,7 @@ files: - name: kviper.zip required: true category: bios_zip - source_ref: "src/mame/konami/viper.cpp:3213" + source_ref: "src/mame/konami/viper.cpp:3267" contents: - name: 941b01.u25 size: 262144 @@ -1513,12 +1513,12 @@ files: required: true category: bios_zip system: konami-twinkle - source_ref: "src/mame/konami/twinkle.cpp:1624" + source_ref: "src/mame/konami/twinkle.cpp:1655" - name: bubsys.zip required: true category: bios_zip - source_ref: "src/mame/konami/nemesis.cpp:3140" + source_ref: "src/mame/konami/nemesis.cpp:3246" contents: - name: boot.bin size: 480 @@ -1540,7 +1540,7 @@ files: - name: konendev.zip required: true category: bios_zip - source_ref: "src/mame/konami/konendev.cpp:909" + source_ref: "src/mame/konami/konendev.cpp:914" contents: - name: 2v02s502_ifu.u190 size: 524288 @@ -1572,7 +1572,7 @@ files: required: true category: bios_zip system: capcom-zn1 - source_ref: "src/mame/sony/zn.cpp:5971" + source_ref: "src/mame/sony/zn.cpp:5967" contents: - name: m534002c-13.ic353 description: japan @@ -1593,7 +1593,7 @@ files: required: true category: bios_zip system: capcom-zn2 - source_ref: "src/mame/sony/zn.cpp:6057" + source_ref: "src/mame/sony/zn.cpp:6053" contents: - name: m534002c-59.ic353 size: 524288 @@ -1607,7 +1607,7 @@ files: - name: coh1000t.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:5991" + source_ref: "src/mame/sony/zn.cpp:5987" contents: - name: m534002c-14.ic353 size: 524288 @@ -1621,7 +1621,7 @@ files: - name: coh1000a.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6017" + source_ref: "src/mame/sony/zn.cpp:6013" contents: - name: m534002c-15.ic353 size: 524288 @@ -1635,7 +1635,7 @@ files: - name: coh1000w.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6039" + source_ref: "src/mame/sony/zn.cpp:6022" contents: - name: msm27c402zb.ic353 size: 524288 @@ -1649,7 +1649,7 @@ files: - name: coh1001l.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6043" + source_ref: "src/mame/sony/zn.cpp:6026" contents: - name: m534002c-17.ic353 size: 524288 @@ -1663,7 +1663,7 @@ files: - name: coh1002v.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6034" + source_ref: "src/mame/sony/zn.cpp:6030" contents: - name: coh-1002v.ic353 size: 524288 @@ -1677,7 +1677,7 @@ files: - name: coh1002e.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6040" + source_ref: "src/mame/sony/zn.cpp:6036" contents: - name: m27c402cz-54.ic353 size: 524288 @@ -1691,7 +1691,7 @@ files: - name: coh1002m.zip required: true category: bios_zip - source_ref: "src/mame/sony/zn.cpp:6091" + source_ref: "src/mame/sony/zn.cpp:6087" contents: - name: m534002c-61.ic353 size: 524288 @@ -1706,7 +1706,7 @@ files: - name: coh3002t.zip required: true category: bios_zip - source_ref: "src/mame/sony/taitogn.cpp:1341" + source_ref: "src/mame/sony/taitogn.cpp:1377" contents: - name: m534002c-60.ic353 size: 524288 @@ -1748,7 +1748,7 @@ files: - name: coh1002t.zip required: true category: bios_zip - source_ref: "src/mame/sony/taitogn.cpp:1342" + source_ref: "src/mame/sony/taitogn.cpp:1378" contents: - name: m534002c-14.ic353 size: 524288 @@ -1770,7 +1770,7 @@ files: - name: taitotz.zip required: true category: bios_zip - source_ref: "src/mame/taito/taitotz.cpp:3016" + source_ref: "src/mame/taito/taitotz.cpp:3014" contents: - name: e68-05-1.ic6 size: 524288 @@ -1786,7 +1786,7 @@ files: required: true category: bios_zip system: super-kaneko-nova - source_ref: "src/mame/kaneko/suprnova.cpp:2135" + source_ref: "src/mame/kaneko/suprnova.cpp:2085" contents: - name: sknsj1.u10 size: 524288 @@ -1883,7 +1883,7 @@ files: required: true category: bios_zip system: hyper-neogeo64 - source_ref: "src/mame/snk/hng64.cpp:3238" + source_ref: "src/mame/snk/hng64.cpp:3241" contents: - name: brom1.bin size: 524288 @@ -2098,7 +2098,7 @@ files: - name: maxaflex.zip required: true category: bios_zip - source_ref: "src/mame/atari/maxaflex.cpp:448" + source_ref: "src/mame/atari/maxaflex.cpp:450" contents: - name: atarixl.rom size: 16384 @@ -2117,7 +2117,7 @@ files: - name: crysbios.zip required: true category: bios_zip - source_ref: "src/mame/misc/crystal.cpp:854" + source_ref: "src/mame/misc/crystal.cpp:847" contents: - name: mx27l1000.u14 description: AMG0110B PCB @@ -2140,7 +2140,7 @@ files: - name: aristmk5.zip required: true category: bios_zip - source_ref: "src/mame/acorn/aristmk5.cpp:9303" + source_ref: "src/mame/acorn/aristmk5.cpp:9293" - name: aristmk6.zip required: true @@ -2558,7 +2558,7 @@ files: - name: allied.zip required: true category: bios_zip - source_ref: "src/mame/pinball/allied.cpp:772" + source_ref: "src/mame/pinball/allied.cpp:775" contents: - name: 6530-009.u5 size: 1024 @@ -2576,7 +2576,7 @@ files: - name: gp_110.zip required: true category: bios_zip - source_ref: "src/mame/pinball/gp_1.cpp:575" + source_ref: "src/mame/pinball/gp_1.cpp:577" contents: - name: a-110.u12 size: 2048 @@ -2590,7 +2590,7 @@ files: - name: gts1.zip required: true category: bios_zip - source_ref: "src/mame/pinball/gts1.cpp:1070" + source_ref: "src/mame/pinball/gts1.cpp:1074" contents: - name: a1752cf.u5 size: 2048 @@ -2604,7 +2604,7 @@ files: - name: recel.zip required: true category: bios_zip - source_ref: "src/mame/pinball/recel.cpp:546" + source_ref: "src/mame/pinball/recel.cpp:547" contents: - name: a2361.b1 size: 1024 @@ -2618,7 +2618,7 @@ files: - name: slvrball.zip required: true category: bios_zip - source_ref: "src/mame/misc/silverball.cpp:259" + source_ref: "src/mame/misc/silverball.cpp:258" contents: - name: bios47.bin description: BIOS47 (Acorp 694XT/694XT1) @@ -3018,7 +3018,7 @@ files: - name: tourvis.zip required: true category: bios_zip - source_ref: "src/mame/pce/tourvis.cpp:448" + source_ref: "src/mame/pce/tourvis.cpp:451" contents: - name: v4-60.ic29 description: V4-60 @@ -3079,7 +3079,7 @@ files: - name: v4bios.zip required: true category: bios_zip - source_ref: "src/mame/barcrest/mpu4vid.cpp:8698" + source_ref: "src/mame/barcrest/mpu4vid.cpp:8696" contents: - name: vid.p1 size: 65536 @@ -3099,7 +3099,7 @@ files: - name: pumpitup.zip required: true category: bios_zip - source_ref: "src/mame/misc/xtom3d.cpp:997" + source_ref: "src/mame/misc/xtom3d.cpp:996" contents: - name: mk3_1.0_bios.u22 description: mk3 v1.0 @@ -3321,7 +3321,7 @@ files: required: true category: bios_zip system: entex-advision - source_ref: "src/mame/entex/advision.cpp:357" + source_ref: "src/mame/entex/advision.cpp:471" contents: - name: ins8048-11kdp_n.u5 description: Intel 8048 main CPU ROM @@ -3337,7 +3337,7 @@ files: required: true category: bios_zip system: apf-m1000 - source_ref: "src/mame/apf/apf.cpp:613" + source_ref: "src/mame/apf/apf.cpp:642" contents: - name: apf_4000.rom description: Standard BIOS @@ -3373,7 +3373,7 @@ files: required: true category: bios_zip system: bandai-rx78 - source_ref: "src/mame/bandai/rx78.cpp:559" + source_ref: "src/mame/bandai/rx78.cpp:577" note: "MACHINE_NOT_WORKING." contents: - name: ipl.rom @@ -3830,7 +3830,7 @@ files: required: true category: bios_zip system: pcw - source_ref: "src/mame/amstrad/pcw.cpp:1402" + source_ref: "src/mame/amstrad/pcw.cpp:1460" note: | Amstrad PCW8256 parent ROM set. Z80-based word processor/computer (1985). 6 machines: pcw8256 (parent), pcw8512, pcw9256, pcw9512, pcw9512+, pcw10. @@ -3852,7 +3852,7 @@ files: required: true category: bios_zip system: pcw - source_ref: "src/mame/amstrad/pcw.cpp:1429" + source_ref: "src/mame/amstrad/pcw.cpp:1462" note: | Amstrad PCW9512 clone ROM set. Daisywheel printer variant (1987). Uses different printer MCU (40103.ic109) than 9-pin models. @@ -4276,7 +4276,7 @@ files: - name: ekara.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2956" + source_ref: "src/mame/tvgames/xavix.cpp:2878" contents: - name: ekara.bin size: 1048576 @@ -4286,7 +4286,7 @@ files: - name: ekaraa.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2905" + source_ref: "src/mame/tvgames/xavix.cpp:2879" contents: - name: ekara2.bin size: 1048576 @@ -4296,7 +4296,7 @@ files: - name: ekaraj.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2906" + source_ref: "src/mame/tvgames/xavix.cpp:2880" contents: - name: ekarajapan.bin size: 1048576 @@ -4306,7 +4306,7 @@ files: - name: ekarag.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2959" + source_ref: "src/mame/tvgames/xavix.cpp:2881" contents: - name: ekaragermany.bin size: 2097152 @@ -4316,7 +4316,7 @@ files: - name: ekaras.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2908" + source_ref: "src/mame/tvgames/xavix.cpp:2882" contents: - name: ekaraspanish.bin size: 2097152 @@ -4326,7 +4326,7 @@ files: - name: isinger.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2962" + source_ref: "src/mame/tvgames/xavix.cpp:2884" contents: - name: kr_isinger.bin size: 1048576 @@ -4336,7 +4336,7 @@ files: - name: ekaraphs.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2965" + source_ref: "src/mame/tvgames/xavix.cpp:2887" contents: - name: ekaraheadset.bin size: 2097152 @@ -4346,7 +4346,7 @@ files: - name: epitch.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:3028" + source_ref: "src/mame/tvgames/xavix.cpp:2890" contents: - name: ekarajapan.bin size: 1048576 @@ -4356,7 +4356,7 @@ files: - name: ekaramix.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2919" + source_ref: "src/mame/tvgames/xavix.cpp:2893" contents: - name: ekaramix.bin size: 2097152 @@ -4366,7 +4366,7 @@ files: - name: ddrfammt.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2922" + source_ref: "src/mame/tvgames/xavix.cpp:2896" contents: - name: ekara_ddr_ha010_81947.bin size: 2097152 @@ -4376,7 +4376,7 @@ files: - name: popira.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2936" + source_ref: "src/mame/tvgames/xavix.cpp:2899" contents: - name: popira.bin size: 1048576 @@ -4386,7 +4386,7 @@ files: - name: popirak.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2927" + source_ref: "src/mame/tvgames/xavix.cpp:2901" contents: - name: kr_main.u2 size: 1048576 @@ -4396,7 +4396,7 @@ files: - name: popira2.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2930" + source_ref: "src/mame/tvgames/xavix.cpp:2904" contents: - name: popira2.bin size: 2097152 @@ -4406,7 +4406,7 @@ files: - name: taikodp.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2933" + source_ref: "src/mame/tvgames/xavix.cpp:2907" contents: - name: taikodepopira.bin size: 2097152 @@ -4416,7 +4416,7 @@ files: - name: jpopira.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2936" + source_ref: "src/mame/tvgames/xavix.cpp:2910" contents: - name: jumpingpopira.bin size: 2097152 @@ -4430,7 +4430,7 @@ files: - name: evio.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2966" + source_ref: "src/mame/tvgames/xavix.cpp:2913" contents: - name: evio.bin size: 2097152 @@ -4440,7 +4440,7 @@ files: - name: tak_daig.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2944" + source_ref: "src/mame/tvgames/xavix.cpp:2918" contents: - name: robottransformer_unit.bin size: 2097152 @@ -4450,7 +4450,7 @@ files: - name: gcslottv.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2946" + source_ref: "src/mame/tvgames/xavix.cpp:2920" contents: - name: sammyslotunit.bin size: 2097152 @@ -4460,7 +4460,7 @@ files: - name: hikara.zip required: true category: bios_zip - source_ref: "src/mame/tvgames/xavix.cpp:2951" + source_ref: "src/mame/tvgames/xavix.cpp:2925" contents: - name: hikara.u3 size: 1048576 diff --git a/emulators/mamearcade.yml b/emulators/mamearcade.yml index c5c3bf90..1832b4fd 100644 --- a/emulators/mamearcade.yml +++ b/emulators/mamearcade.yml @@ -219,7 +219,7 @@ files: required: true category: bios_zip system: igs-pgm - source_ref: "src/mame/igs/pgm.cpp:5548" + source_ref: "src/mame/igs/pgm.cpp:5545" contents: - name: pgm_p02s.u20 size: 131072 @@ -502,7 +502,7 @@ files: required: true category: bios_zip system: sammy-atomiswave - source_ref: "src/mame/sega/dc_atomiswave.cpp:1519" + source_ref: "src/mame/sega/dc_atomiswave.cpp:1480" contents: - name: bios0.ic23 size: 131072 @@ -643,7 +643,7 @@ files: required: true category: bios_zip system: sega-stv - source_ref: "src/mame/sega/stv.cpp:4067" + source_ref: "src/mame/sega/stv.cpp:3948" contents: - name: epr-23603.ic8 size: 524288 @@ -1000,7 +1000,7 @@ files: required: true category: bios_zip system: nintendo-playch10 - source_ref: "src/mame/nintendo/playch10.cpp:2981" + source_ref: "src/mame/nintendo/playch10.cpp:2980" contents: - name: pch1-c__8t_e-2.8t size: 16384 @@ -1168,7 +1168,7 @@ files: required: true category: bios_zip system: namco-system573 - source_ref: "src/mame/konami/ksys573.cpp:6541" + source_ref: "src/mame/konami/ksys573.cpp:6415" contents: - name: 700a01.22g description: Standard @@ -1217,7 +1217,7 @@ files: required: true category: bios_zip system: konami-gv - source_ref: "src/mame/konami/konamigv.cpp:1450" + source_ref: "src/mame/konami/konamigv.cpp:1447" contents: - name: 999a01.7e size: 524288 @@ -1247,7 +1247,7 @@ files: required: true category: bios_zip system: konami-twinkle - source_ref: "src/mame/konami/twinkle.cpp:1624" + source_ref: "src/mame/konami/twinkle.cpp:1643" - name: bubsys.zip required: true @@ -1277,7 +1277,7 @@ files: required: true category: bios_zip system: capcom-zn1 - source_ref: "src/mame/sony/zn.cpp:5971" + source_ref: "src/mame/sony/zn.cpp:5969" contents: - name: m534002c-13.ic353 description: japan @@ -1298,7 +1298,7 @@ files: required: true category: bios_zip system: capcom-zn2 - source_ref: "src/mame/sony/zn.cpp:6057" + source_ref: "src/mame/sony/zn.cpp:6055" contents: - name: m534002c-59.ic353 size: 524288 @@ -1313,7 +1313,7 @@ files: required: true category: bios_zip system: taito-fx1 - source_ref: "src/mame/sony/zn.cpp:5991" + source_ref: "src/mame/sony/zn.cpp:5989" contents: - name: m534002c-14.ic353 size: 524288 @@ -1328,7 +1328,7 @@ files: required: true category: bios_zip system: acclaim-zn1 - source_ref: "src/mame/sony/zn.cpp:6017" + source_ref: "src/mame/sony/zn.cpp:6015" contents: - name: m534002c-15.ic353 size: 524288 @@ -1343,7 +1343,7 @@ files: required: true category: bios_zip system: atari-zn1 - source_ref: "src/mame/sony/zn.cpp:6039" + source_ref: "src/mame/sony/zn.cpp:6024" contents: - name: msm27c402zb.ic353 size: 524288 @@ -1358,7 +1358,7 @@ files: required: true category: bios_zip system: atlus-zn1 - source_ref: "src/mame/sony/zn.cpp:6043" + source_ref: "src/mame/sony/zn.cpp:6028" contents: - name: m534002c-17.ic353 size: 524288 @@ -1373,7 +1373,7 @@ files: required: true category: bios_zip system: videosystem-zn1 - source_ref: "src/mame/sony/zn.cpp:6034" + source_ref: "src/mame/sony/zn.cpp:6032" contents: - name: coh-1002v.ic353 size: 524288 @@ -1388,7 +1388,7 @@ files: required: true category: bios_zip system: eighting-zn1 - source_ref: "src/mame/sony/zn.cpp:6040" + source_ref: "src/mame/sony/zn.cpp:6038" contents: - name: m27c402cz-54.ic353 size: 524288 @@ -1403,7 +1403,7 @@ files: required: true category: bios_zip system: tecmo-tps - source_ref: "src/mame/sony/zn.cpp:6091" + source_ref: "src/mame/sony/zn.cpp:6089" contents: - name: m534002c-61.ic353 size: 524288 @@ -1754,7 +1754,7 @@ files: required: true category: bios_zip system: exidy-maxaflex - source_ref: "src/mame/atari/maxaflex.cpp:448" + source_ref: "src/mame/atari/maxaflex.cpp:447" contents: - name: atarixl.rom size: 16384 @@ -1774,7 +1774,7 @@ files: required: true category: bios_zip system: brezzasoft-crystal - source_ref: "src/mame/misc/crystal.cpp:854" + source_ref: "src/mame/misc/crystal.cpp:845" contents: - name: mx27l1000.u14 description: AMG0110B PCB diff --git a/emulators/mamemess.yml b/emulators/mamemess.yml index cc14ea58..99c1d50b 100644 --- a/emulators/mamemess.yml +++ b/emulators/mamemess.yml @@ -482,7 +482,7 @@ files: required: true category: bios_zip system: apple2 - source_ref: "src/mame/apple/apple2.cpp:665" + source_ref: "src/mame/apple/apple2.cpp:1310" contents: - name: a2.chr description: Character generator ROM @@ -513,7 +513,7 @@ files: required: true category: bios_zip system: apple2 - source_ref: "src/mame/apple/apple2.cpp:803" + source_ref: "src/mame/apple/apple2.cpp:1311" contents: - name: 341-0036.chr description: Character generator ROM @@ -548,7 +548,7 @@ files: required: true category: bios_zip system: apple2 - source_ref: "src/mame/apple/apple2e.cpp:5566" + source_ref: "src/mame/apple/apple2e.cpp:6345" contents: - name: 342-0133-a.chr description: Character generator ROM @@ -571,7 +571,7 @@ files: required: true category: bios_zip system: apple2 - source_ref: "src/mame/apple/apple2e.cpp:5688" + source_ref: "src/mame/apple/apple2e.cpp:6352" contents: - name: 342-0265-a.chr description: Enhanced character generator ROM @@ -818,7 +818,7 @@ files: required: true category: bios_zip system: entex-advision - source_ref: "src/mame/entex/advision.cpp:357" + source_ref: "src/mame/entex/advision.cpp:471" contents: - name: ins8048-11kdp_n.u5 description: Intel 8048 main CPU ROM @@ -834,7 +834,7 @@ files: required: true category: bios_zip system: bandai-rx78 - source_ref: "src/mame/bandai/rx78.cpp:559" + source_ref: "src/mame/bandai/rx78.cpp:577" note: "MACHINE_NOT_WORKING." contents: - name: ipl.rom diff --git a/scripts/mame_ref_audit.py b/scripts/mame_ref_audit.py new file mode 100644 index 00000000..1e5b2efb --- /dev/null +++ b/scripts/mame_ref_audit.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +"""Check that each MAME romset ref names the line declaring its own set. + +profile_sync follows content: a ref that drifted still anchors wherever the +cited text went, which is what drift detection is for. It cannot say whether +the line a MAME ref points at declares the set the entry is named after, and +that is the only thing such a ref means. Asking the stronger question found +nineteen stale refs in one driver file where profile_sync had flagged five. + +The set name is argument 1 of the machine macro, after the year. Matching the +name anywhere on the line would also match every clone that names this set as +its parent, which is most of a driver file. Comments are stripped first: a +declaration can sit behind one, as `/* Naomi */ GAME( 1998, naomi, ...)` does. + +A set no machine macro declares is not an error. Device ROMs take the +shortname of their DEFINE_DEVICE_TYPE and some archives are bare ROM_START +blocks; a ref there cites something this check cannot judge, and says so. +""" +from __future__ import annotations + +import argparse +import os +import re +import sys +from dataclasses import dataclass + +sys.path.insert(0, os.path.dirname(__file__)) + +import upstream +from safeparse import yaml_load +from scraper.mame_parser import _MACHINE_MACROS, strip_comments + +DRIVER_REF = re.compile(r"^(src/[\w./+-]+):(\d+)$") + + +@dataclass(frozen=True) +class Finding: + set_name: str + path: str + cited: int + declared: int + + +def declares(line: str, set_name: str) -> bool: + """Whether this line is the machine declaration of that set.""" + clean = strip_comments(line) + match = _MACHINE_MACROS.search(clean) + if not match: + return False + args = clean[match.end():].split(",") + return len(args) > 1 and args[1].strip() == set_name + + +def audit(name: str, emulators_dir: str, cache_dir: str, offline: bool): + """Findings, plus counts of refs that agree and of unjudgeable ones.""" + with open(os.path.join(emulators_dir, f"{name}.yml"), encoding="utf-8") as handle: + document = yaml_load(handle) or {} + repo = upstream.parse_repo(str(document.get("source") or "")) + pin = str(document.get("source_commit") or "") + if repo is None or not pin: + return [], 0, 0 + sources: dict[str, list[str] | None] = {} + findings: list[Finding] = [] + agreed = unjudged = 0 + for entry in document.get("files", []) or []: + entry_name = str(entry.get("name", "")) + match = DRIVER_REF.match(str(entry.get("source_ref") or "")) + if not (entry_name.endswith(".zip") and match): + continue + path, cited = match.group(1), int(match.group(2)) + if path not in sources: + sources[path] = upstream.fetch_file(repo, pin, path, cache_dir, offline) + lines = sources[path] + if lines is None: + continue + set_name = entry_name[:-4] + if cited <= len(lines) and declares(lines[cited - 1], set_name): + agreed += 1 + continue + found = [i for i, line in enumerate(lines, 1) if declares(line, set_name)] + if len(found) != 1: + # None: a device set or a bare ROM_START. Several: the driver + # declares the name twice and only a reader can choose. + unjudged += 1 + continue + findings.append(Finding(set_name, path, cited, found[0])) + return findings, agreed, unjudged + + +def rewrite(name: str, emulators_dir: str, findings: list[Finding]) -> int: + """Point each ref at the declaration, one entry at a time.""" + path = os.path.join(emulators_dir, f"{name}.yml") + with open(path, encoding="utf-8") as handle: + text = handle.read() + written = 0 + for finding in findings: + anchor = f"- name: {finding.set_name}.zip" + old = f'source_ref: "{finding.path}:{finding.cited}"' + start = text.find(anchor) + if start < 0: + continue + at = text.find(old, start) + if at < 0: + continue + new = f'source_ref: "{finding.path}:{finding.declared}"' + text = text[:at] + new + text[at + len(old):] + written += 1 + if written: + with open(path, "w", encoding="utf-8") as handle: + handle.write(text) + return written + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("emulators", nargs="+") + parser.add_argument("--emulators-dir", default="emulators") + parser.add_argument("--cache-dir", default=".cache") + parser.add_argument("--offline", action="store_true") + parser.add_argument("--write", action="store_true") + args = parser.parse_args() + + total = 0 + for name in args.emulators: + findings, agreed, unjudged = audit( + name, args.emulators_dir, args.cache_dir, args.offline + ) + total += len(findings) + print( + f"{name}: {agreed} agree, {len(findings)} point elsewhere, " + f"{unjudged} not judgeable" + ) + for finding in findings: + print( + f" {finding.set_name:16} {finding.path}" + f":{finding.cited} -> {finding.declared}" + ) + if args.write and findings: + print(f" written: {rewrite(name, args.emulators_dir, findings)}") + raise SystemExit(1 if total and not args.write else 0) + + +if __name__ == "__main__": + main() diff --git a/tests/test_mame_ref_audit.py b/tests/test_mame_ref_audit.py new file mode 100644 index 00000000..cbba5dbd --- /dev/null +++ b/tests/test_mame_ref_audit.py @@ -0,0 +1,127 @@ +"""A MAME romset ref must name the line declaring its own set. + +profile_sync follows content, so a drifted ref still anchors wherever the +cited text went. That is drift detection working, and it cannot answer the +only question a MAME ref asks: does this line declare this set. Asking it +found nineteen stale refs in one driver where profile_sync had flagged five. +""" +from __future__ import annotations + +import sys +import tempfile +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(ROOT / "scripts")) + +import mame_ref_audit +from mame_ref_audit import declares + + +DRIVER = [ + "// a driver file", + "CONS( 2000, ekara, 0, 0, m, i, s, init, \"Takara\", \"e-kara\", F )", + "CONS( 2002, ekarag, ekara, 0, m, i, s, init, \"Takara\", \"e-kara DE\", F )", + "/* Naomi */ GAME( 1998, naomi, 0, n, n, s, init, ROT0, \"Sega\", \"Naomi\", F )", + "ROM_START( soundbox )", +] + +PROFILE = """emulator: Test +source: "https://github.com/libretro/mame" +source_commit: "pinsha" +files: + - name: ekara.zip + category: bios_zip + source_ref: "src/mame/tvgames/xavix.cpp:99" + - name: ekarag.zip + category: bios_zip + source_ref: "src/mame/tvgames/xavix.cpp:3" + - name: soundbox.zip + category: bios_zip + source_ref: "src/mame/sega/segaai.cpp:1" +""" + + +class TestDeclares(unittest.TestCase): + def test_the_set_name_is_argument_one(self): + self.assertTrue(declares(DRIVER[1], "ekara")) + + def test_a_clone_naming_it_as_parent_is_not_a_declaration(self): + """ekara is the parent field of ekarag; most of a driver looks so.""" + self.assertFalse(declares(DRIVER[2], "ekara")) + self.assertTrue(declares(DRIVER[2], "ekarag")) + + def test_a_declaration_behind_a_comment_still_counts(self): + self.assertTrue(declares(DRIVER[3], "naomi")) + + def test_a_rom_start_is_not_a_machine_declaration(self): + self.assertFalse(declares(DRIVER[4], "soundbox")) + + +class TestAudit(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.dir = self.tmp.name + Path(self.dir, "p.yml").write_text(PROFILE, encoding="utf-8") + self._fetch = mame_ref_audit.upstream.fetch_file + mame_ref_audit.upstream.fetch_file = ( + lambda repo, sha, path, cache, offline=False: + DRIVER if path.endswith("xavix.cpp") else ["ROM_START( soundbox )"] + ) + + def tearDown(self): + mame_ref_audit.upstream.fetch_file = self._fetch + self.tmp.cleanup() + + def test_a_ref_pointing_elsewhere_is_reported_with_its_declaration(self): + findings, agreed, unjudged = mame_ref_audit.audit("p", self.dir, ".c", False) + self.assertEqual(agreed, 1, "ekarag cites its own line") + self.assertEqual([f.set_name for f in findings], ["ekara"]) + self.assertEqual(findings[0].cited, 99) + self.assertEqual(findings[0].declared, 2) + + def test_a_set_no_machine_declares_is_left_unjudged(self): + """A device archive takes its DEFINE_DEVICE_TYPE shortname.""" + _, _, unjudged = mame_ref_audit.audit("p", self.dir, ".c", False) + self.assertEqual(unjudged, 1) + + def test_rewrite_moves_only_the_entry_that_owns_the_ref(self): + findings, _, _ = mame_ref_audit.audit("p", self.dir, ".c", False) + self.assertEqual(mame_ref_audit.rewrite("p", self.dir, findings), 1) + text = Path(self.dir, "p.yml").read_text(encoding="utf-8") + self.assertIn('source_ref: "src/mame/tvgames/xavix.cpp:2"', text) + self.assertIn( + 'source_ref: "src/mame/tvgames/xavix.cpp:3"', text, + "ekarag's own ref must be untouched", + ) + + def test_a_corrected_profile_reports_nothing(self): + findings, _, _ = mame_ref_audit.audit("p", self.dir, ".c", False) + mame_ref_audit.rewrite("p", self.dir, findings) + again, agreed, _ = mame_ref_audit.audit("p", self.dir, ".c", False) + self.assertEqual(again, []) + self.assertEqual(agreed, 2) + + +class TestCorpusStaysCorrect(unittest.TestCase): + """The committed profiles agree with their pinned drivers. + + Offline, so it reads the fetch cache: skipped where that is cold rather + than turning a network absence into a failure. + """ + + def test_every_mame_family_ref_names_its_own_set(self): + if not (ROOT / ".cache").is_dir(): + self.skipTest("no upstream cache") + for name in ("mame", "mamearcade", "mamemess", "groovymame"): + with self.subTest(emulator=name): + findings, agreed, _ = mame_ref_audit.audit( + name, str(ROOT / "emulators"), str(ROOT / ".cache"), True + ) + if not agreed and not findings: + self.skipTest(f"{name}: driver sources not cached") + self.assertEqual( + [f.set_name for f in findings], [], + f"{name} has refs that do not declare their own set", + ) diff --git a/wiki/tools.md b/wiki/tools.md index 10c61833..bf111d1a 100644 --- a/wiki/tools.md +++ b/wiki/tools.md @@ -238,6 +238,34 @@ to the files inside the archive, so the exported DAT lists those entries without a container sha1. Anyone submitting the DAT upstream should mention this. +### mame_ref_audit.py + +Checks that each MAME romset ref names the line declaring its own set, at the +profile's pinned revision. + +```bash +python scripts/mame_ref_audit.py mame mamearcade mamemess groovymame +python scripts/mame_ref_audit.py mame --write +``` + +`profile_sync` follows content: a ref that drifted still anchors wherever the +cited text went, which is what drift detection is for. It cannot answer the +only question a MAME ref asks, whether that line declares that set. Asking the +stronger question found nineteen stale refs in one driver file where +profile_sync had flagged five, and ninety-two across the four profiles whose +upstream still moves. + +The set name is argument 1 of the machine macro, after the year: matching it +anywhere on the line would also match every clone naming that set as its +parent, which is most of a driver file. Comments are stripped first, since a +declaration can sit behind one, as `/* Naomi */ GAME( 1998, naomi, ...)` does. + +A set no machine macro declares is reported as not judgeable rather than +wrong: device ROMs take the shortname of their `DEFINE_DEVICE_TYPE`, and some +archives are bare `ROM_START` blocks. The frozen generations, mame2009 through +mame2016, come out clean, which is the check saying it finds drift only where +drift can happen. + ### profile_sync.py Confront a profile with its upstream. The pinned commit is the profile's