Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
31b8d26
Merge master into develop after v2.3.0 release
JoeMatt May 7, 2026
ebb9b7f
ci: Bump cirrus-actions/rebase in the actions-minor-patch group
dependabot[bot] May 7, 2026
bcd078c
ci: Bump actions/upload-artifact from 4 to 7
dependabot[bot] May 7, 2026
eb8a55b
ci: Bump actions/labeler from 5 to 6
dependabot[bot] May 7, 2026
a7c70ff
ci: Bump actions/cache from 4 to 5
dependabot[bot] May 7, 2026
eb21f3d
ci: Bump codecov/codecov-action from 5 to 6
dependabot[bot] May 7, 2026
16e2023
Merge pull request #176 from libretro/dependabot/github_actions/devel…
JoeMatt May 7, 2026
e4aced8
Merge pull request #175 from libretro/dependabot/github_actions/devel…
JoeMatt May 7, 2026
e802237
Merge pull request #174 from libretro/dependabot/github_actions/devel…
JoeMatt May 7, 2026
e81d645
Merge pull request #173 from libretro/dependabot/github_actions/devel…
JoeMatt May 7, 2026
12d48f0
Merge pull request #172 from libretro/dependabot/github_actions/devel…
JoeMatt May 7, 2026
6f58325
git ignore test_frame_timing
JoeMatt May 7, 2026
8d61f86
test(audio): add presence/envelope check to catch silencing regressions
JoeMatt May 8, 2026
43fea2c
docs(claude): require both audio tests for DSP/audio changes
JoeMatt May 8, 2026
56939d5
CD Tier 1: import library subsystem from #109
JoeMatt Apr 29, 2026
40a23d3
CD Tier 2: wire libretro.c CD detection and BIOS loading
JoeMatt Apr 29, 2026
8d11002
CD Tier 3: wire core/jaguar HLE dispatch and BUTCH-CD strategy hooks
JoeMatt Apr 29, 2026
2f25682
CD Tier 4: import CD test suites, dev tools, and framework headers
JoeMatt Apr 29, 2026
4844f6b
HLE CD_read: respect streaming continuation in raw-fallback + counter…
JoeMatt Apr 29, 2026
77eaa23
CD BIOS scan list: accept .rom and .bin variants
JoeMatt Apr 29, 2026
3279b30
CD: fix BUTCH->GPU IRQ line - route to GPU IRQ0 (EXT1), not IRQ1 (DSP)
JoeMatt Apr 29, 2026
14e29e6
CD: tick BUTCHExec from HalflineCallback when CD content is loaded
JoeMatt Apr 29, 2026
bbf9d70
CD: stop suppressing HLETransferTick after N seeks; drop m68k_set_irq…
JoeMatt Apr 29, 2026
7350c9a
test: instrument CD boot harness with GPU PC + IRQ + BUTCH counters
JoeMatt Apr 29, 2026
5cadd99
CD: drop redundant hacks obsoleted by recent CPU/GPU/DSP/IRQ fixes
JoeMatt Apr 29, 2026
13d441a
CD: clear dsaResponseReady on DSCNTRL read (DSA-ack semantics)
JoeMatt Apr 29, 2026
8ad2be8
CD-HLE: drop dead helpers + defer CD_poll completion (HLE 5/9 -> 6/9)
JoeMatt Apr 29, 2026
e206bfd
fix(cd): expose CD test ABI symbols, gate CD EEPROM size on cd_mode
JoeMatt May 7, 2026
31a6629
fix(cd): don't double-reset after CD/cart boot strategy completes
JoeMatt May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/acid-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

- name: Cache vasm
id: vasm-cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: /usr/local/bin/vasmm68k_mot
# Bust the cache if anyone bumps prb28/vasm SHA.
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:

- name: Upload artefacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: acid-results
path: |
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ jobs:
run: bash test/tools/test_rcheevos_e2e.sh ./${{ matrix.config.artifact }}

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.config.displayTargetName }}
path: ${{ matrix.config.artifact }}
Expand Down Expand Up @@ -356,7 +356,7 @@ jobs:
run: make -j4 platform=vita

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: PS Vita
path: virtualjaguar_libretro_vita.a
Expand All @@ -376,7 +376,7 @@ jobs:
DEVKITPRO: /opt/devkitpro

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: Nintendo Switch
path: virtualjaguar_libretro_libnx.a
Expand Down Expand Up @@ -418,7 +418,7 @@ jobs:
bash scripts/gen-version-h.sh
make coverage CC="gcc" CXX="g++"
- name: Upload to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
files: ./coverage.xml
fail_ci_if_error: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v6
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
sync-labels: true
2 changes: 1 addition & 1 deletion .github/workflows/rebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.4
uses: cirrus-actions/rebase@1.8
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/regression-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:

- name: Upload diff artifacts
if: failure()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: regression-diffs-${{ matrix.config.platform }}
path: regression-diffs/
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ jobs:
rm "dist/${DBG}"

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: virtualjaguar_libretro-${{ matrix.config.platform }}
path: dist/
Expand Down Expand Up @@ -310,7 +310,7 @@ jobs:
rm "dist/${OUT}.debug"

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: virtualjaguar_libretro-vita
path: dist/
Expand Down Expand Up @@ -346,7 +346,7 @@ jobs:
rm "dist/${OUT}.debug"

- name: Upload artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: virtualjaguar_libretro-switch
path: dist/
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ test/test_blitter_simd
test/test_blitter_scalar
test/test_*
!test/test_*.c
!test/test_*.h
!test/test_*.sh
!test/test_*.py
test/tools/test_memory_map
Expand Down Expand Up @@ -71,3 +72,4 @@ test/tools/build/
# Acid-test build outputs
test/acid/acid_run
test/acid/tests/**/*.jag
/test/tools/test_frame_timing
16 changes: 15 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ To add a new probe: create `test/harness/foo_probe.h` + `.c`, resolve symbols vi
- `test/regression_test.sh` — screenshot regression vs `test/baselines/` via miniretro (built from source on first run; `MINIRETRO_BIN` env to skip the build)
- `test/tools/test_dsp_audio_diag.c` — DSP audio diagnostic (`make dsp-diag DSP_DIAG_ROM=path`); detects PC escape, bank init failures, silent LTXD
- `test/tools/test_frame_timing.c` — per-frame timing diagnostic (`make frame-timing FRAME_TIMING_ROM=path`); reports halflines/cycles/VBlanks per frame, wall-clock speed ratio, anomaly detection. Use `--csv` for per-frame data, `--json` for machine output
- `test/test_audio_clipping.c` — detects loud-broken audio (saturation density, run length, sustained loud RMS). Catches the Skyhammer / IS2 "saturated square wave" failure mode.
- `test/test_audio_presence.c` — counterpart to clipping: asserts audio is present in a known-good envelope (RMS within `[floor, ceiling]`, onset reached, no long zero runs). **Required to catch the silencing-regression class** where a "fix" drops RMS to zero — clipping passes but the game has no audio. Iron Soldier 1 baseline: RMS ~1175 on develop.
- `test/tools/test_memory_map.c` — asserts `SET_MEMORY_MAPS`, `SET_SUPPORT_ACHIEVEMENTS=true`, descriptor layout
- `test/tools/test_blitter_compare` — fast vs accurate blitter diff
- `test/test_dsp_mac40.c` — DSP 40-bit MAC accumulator (`dsp_acc40.h`)
Expand All @@ -95,6 +97,18 @@ To add a new probe: create `test/harness/foo_probe.h` + `.c`, resolve symbols vi

`make benchmark` runs `test/tools/test_benchmark` headlessly against a fixed ROM (default `test/roms/yarc.j64`, 600 frames) and prints FPS / ms-per-frame. Use as a same-host commit-to-commit delta — don't compare across machines. Full guide: [`docs/profiling.md`](docs/profiling.md) covers Instruments / `perf` / flame graphs and the SIMD A/B knob.

### Audio / DSP work — required tests

**Any change to `src/jerry/dac.c`, `src/jerry/dsp.c`, the HLE BIOS DSP/audio engine path in `src/core/jaguar.c`, or the DSP IRQ return-address logic MUST be validated against both audio tests, not just one.** A clipping check alone is insufficient: PR #170 (closed) shipped a "fix" that took Iron Soldier 2 from 17% saturated samples to RMS=521 (silent), and the clipping test passed because silence has 0% saturation.

Required runs before declaring an audio change done:

1. `make TEST_EXPORTS=1 test` — must exit 0. Both `test_audio_clipping` and `test_audio_presence` are part of the suite. The presence check on Iron Soldier 1 uses develop's measured envelope (`--rms-floor 200 --rms-ceiling 25000`). If your change moves IS1's RMS outside that band, you've changed audio behavior — verify it's intentional.
2. Sanity-check that previously-clipping titles (Skyhammer, IS2) didn't go from "loud broken" to "silent broken". Skyhammer should still fail clipping until it's actually fixed; if it suddenly passes clipping but presence drops to silence, that's the masked-failure pattern.
3. **Verify in RetroArch on a real game.** Headless tests cannot tell "music plays" from "structured noise at the right RMS" or catch BIOS-mode crashes. Memory: PR #170's BIOS crash + HLE silence in Skyhammer were both invisible to the test suite.

Do not relax thresholds in `test_audio_clipping.c` or `test_audio_presence.c` to make a PR pass. If a real fix makes a known-broken title legitimately quieter, that's a separate, deliberate baseline update — call it out in the commit, not as a side effect.

### Headless framebuffer caveat

The miniretro harness used by `test/regression_test.sh` doesn't expose the same composited framebuffer that RetroArch reads. Symptom: `jag_240p_test_suite` main menu shows ~1k non-black pixels via miniretro vs tens of thousands via RetroArch. Treat that as a **headless read-path / presentation bug** (OP+blitter output vs what the host reads), not a 240p timing or `__muldi3` performance bug. Verify against RetroArch before treating a regression as real.
Expand All @@ -118,7 +132,7 @@ When spawning agents for work in this repo, include these rules:
1. **C89 strict.** No mid-block declarations, no `for(int i…)`, no C99. All vars at top of block. Run `bash scripts/c89-lint.sh src/YOURFILE.c` before declaring done.
2. **Branch from develop.** Use `git worktree` or branch off develop. Never target main.
3. **Hardware reference.** For any emulation-accuracy work, read `docs/jtrm-*.md` first. Do NOT trust source-code comments for clock rates or register behavior.
4. **Test after changes.** Run `make -j$(getconf _NPROCESSORS_ONLN)` to verify build. Run `make test` for the full suite. For blitter changes, also run `test/tools/test_blitter_compare` if available.
4. **Test after changes.** Run `make -j$(getconf _NPROCESSORS_ONLN)` to verify build. Run `make test` for the full suite. For blitter changes, also run `test/tools/test_blitter_compare` if available. **For audio / DSP / HLE-engine changes**, both `test_audio_clipping` and `test_audio_presence` must pass; running only one masks the silencing-regression class (see "Audio / DSP work — required tests" above). Verify in RetroArch on a real game before declaring done — headless tests cannot tell music from structured noise, and they don't catch BIOS-mode crashes.
5. **No unnecessary changes.** Don't refactor surrounding code, add abstractions, or clean up unrelated files. Surgical changes only.
6. **Commit message style.** Use conventional commits: `fix(component):`, `perf(component):`, `test(component):`, `docs:`.

Expand Down
88 changes: 85 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -731,9 +731,13 @@ clean:
test/test_dsp_ops test/test_dsp_unit test/test_hle_bios \
test/test_subsystem_init test/test_subsystem_timeline \
test/test_irq_cascade test/test_boot_patterns test/test_audio_pipeline \
test/test_audio_clipping test/test_pit_clock_rate \
test/test_audio_clipping test/test_audio_presence test/test_pit_clock_rate \
test/test_blitter_mmio test/test_eeprom_lifecycle \
test/test_tom_visible_window test/test_framebuffer_integrity \
test/test_butch_cd test/test_bios_config test/test_boot_config \
test/test_cd_boot test/test_cd_hle_boot test/test_cd_bios_boot \
test/test_audio_dac test/test_blitter \
test/dump_pc test/heap_search \
test/tools/test_memory_map test/tools/test_dsp_audio_diag \
test/tools/test_frame_timing

Expand Down Expand Up @@ -761,9 +765,13 @@ test: test/test_cheat test/test_event_queue test/test_blitter_simd test/test_dsp
$(TARGET) test/test_m68k_ops test/test_gpu_ops test/test_dsp_ops \
test/test_dsp_unit test/test_hle_bios test/test_subsystem_init \
test/test_subsystem_timeline test/test_irq_cascade test/test_boot_patterns \
test/test_audio_pipeline test/test_audio_clipping test/test_pit_clock_rate \
test/test_audio_pipeline test/test_audio_clipping test/test_audio_presence test/test_pit_clock_rate \
test/test_blitter_mmio test/test_eeprom_lifecycle test/test_tom_visible_window \
test/test_framebuffer_integrity test/tools/test_memory_map
test/test_framebuffer_integrity \
test/test_butch_cd test/test_bios_config test/test_boot_config \
test/test_cd_boot test/test_cd_hle_boot test/test_cd_bios_boot \
test/test_audio_dac test/test_blitter \
test/tools/test_memory_map
./test/test_cheat
./test/test_event_queue
./test/test_blitter_mmio
Expand Down Expand Up @@ -801,6 +809,21 @@ test: test/test_cheat test/test_event_queue test/test_blitter_simd test/test_dsp
else \
echo " SKIP: Iron Soldier 2 ROM (private) not available"; \
fi
@# Presence check: counterpart to the clipping check. A "fix" that
@# silences the game (e.g. PR #170 closed without merge) drops RMS
@# to zero — clipping passes but the game has no audio. Iron
@# Soldier 1 boots straight to a music-on title; envelope was
@# measured on develop (RMS ~1175). Floor 200 catches silence
@# regressions; ceiling 25000 catches loud-broken regressions.
@if [ -f "test/roms/private/Iron Soldier (1994).jag" ]; then \
./test/test_audio_presence ./$(TARGET) "test/roms/private/Iron Soldier (1994).jag" --label "Iron Soldier 1" --rms-floor 200 --rms-ceiling 25000 --quiet; \
else \
echo " SKIP: Iron Soldier 1 ROM (private) not available (audio presence)"; \
fi
./test/test_butch_cd
./test/test_bios_config
./test/test_boot_config
./test/test_audio_dac
./test/tools/test_memory_map ./$(TARGET)
@# Framebuffer integrity: alpha corruption + screen position shift detection.
@if [ -f "test/roms/yarc.j64" ]; then \
Expand All @@ -812,6 +835,13 @@ test: test/test_cheat test/test_event_queue test/test_blitter_simd test/test_dsp
@$(CC) -O2 -Wall -o /tmp/gen_eeprom_test_rom test/tools/gen_eeprom_test_rom.c && \
/tmp/gen_eeprom_test_rom /tmp/eeprom_lifecycle_test.j64 && \
./test/test_eeprom_lifecycle ./$(TARGET) /tmp/eeprom_lifecycle_test.j64
@echo ""
@echo "Note: test/test_cd_boot, test/test_cd_hle_boot, test/test_cd_bios_boot,"
@echo "and test/test_blitter (register-readback) are built but not run from"
@echo "'make test'. The CD sweeps walk every disc in test/roms/private/; the"
@echo "blitter readback tests probe register read paths that the emulator"
@echo "does not currently expose. Invoke them directly when validating"
@echo "regressions in those subsystems."

test/test_cheat: test/test_cheat.c src/core/cheat.c src/core/cheat.h
$(CC) -O2 -Wall -std=c99 $(INCFLAGS) \
Expand Down Expand Up @@ -892,6 +922,10 @@ test/test_audio_clipping: test/test_audio_clipping.c
$(CC) -O2 -Wall -std=c99 $(INCFLAGS) \
-o $@ test/test_audio_clipping.c -ldl -lm

test/test_audio_presence: test/test_audio_presence.c
$(CC) -O2 -Wall -std=c99 $(INCFLAGS) \
-o $@ test/test_audio_presence.c -ldl -lm

test/tools/test_memory_map: test/tools/test_memory_map.c
$(CC) -O2 -Wall -std=c99 $(INCFLAGS) \
-o $@ test/tools/test_memory_map.c -ldl
Expand All @@ -917,6 +951,54 @@ test/test_framebuffer_integrity: test/test_framebuffer_integrity.c \
-o $@ test/test_framebuffer_integrity.c \
test/harness/harness.c \
$(if $(filter Linux,$(shell uname -s)),-ldl) -lm

# CD-specific test harnesses (imported from PR #109). Tests SKIP gracefully
# when no disc images are present in test/roms/private/, so CI without
# private ROMs still passes.
test/test_butch_cd: test/test_butch_cd.c test/test_framework.h test/mister_ground_truth.h
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_butch_cd.c -ldl

test/test_bios_config: test/test_bios_config.c
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_bios_config.c -ldl

test/test_boot_config: test/test_boot_config.c
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_boot_config.c -ldl

test/test_cd_boot: test/test_cd_boot.c
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_cd_boot.c -ldl

test/test_cd_hle_boot: test/test_cd_hle_boot.c test/test_framework.h test/cd_assertions.h
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_cd_hle_boot.c -ldl

test/test_cd_bios_boot: test/test_cd_bios_boot.c test/test_framework.h test/cd_assertions.h
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_cd_bios_boot.c -ldl

test/test_audio_dac: test/test_audio_dac.c test/test_framework.h
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_audio_dac.c -ldl -lm

test/test_blitter: test/test_blitter.c test/test_framework.h
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/test_blitter.c -ldl

# Diagnostic CD harnesses: invoked manually with a CUE/CHD argument.
test/dump_pc: test/dump_pc.c
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/dump_pc.c -ldl

test/heap_search: test/heap_search.c
$(CC) -O2 -Wall -Wno-unused-function -Wno-unused-variable -std=c99 $(INCFLAGS) \
-o $@ test/heap_search.c -ldl

# Aggregate target for the manual diagnostic tools.
.PHONY: tools
tools: test/dump_pc test/heap_search test/test_cd_boot
endif

.PHONY: clean test lint coverage benchmark acid dsp-diag frame-timing
Expand Down
3 changes: 3 additions & 0 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ SOURCES_C := \
$(CORE_DIR)/src/tom/tom.c \
$(CORE_DIR)/src/cd/cdintf.c \
$(CORE_DIR)/src/cd/cdrom.c \
$(CORE_DIR)/src/cd/jagcd_bios.c \
$(CORE_DIR)/src/cd/jagcd_cart.c \
$(CORE_DIR)/src/cd/jagcd_hle.c \
$(CORE_DIR)/src/core/cheat.c \
$(CORE_DIR)/src/core/crc32.c \
$(CORE_DIR)/src/core/perf_counters.c \
Expand Down
7 changes: 7 additions & 0 deletions exports-test.list
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ _perf_counters_dump
_perf_counters_reset
_perf_counters_register
_perf_counters_find
_CDROM*
_BUTCH*
_GetRamPtr
_bootConfig
_cd_boot_strategy_*
_jaguar_cd_*
_ResolveBootConfig
Loading
Loading