Skip to content

feat(genesis): Significantly improve performance, splitting emulation across both cores for 60fps with audio no frameskip required 🚀#110

Merged
finger563 merged 16 commits into
mainfrom
feat/gen-dualcore
Jun 20, 2026
Merged

feat(genesis): Significantly improve performance, splitting emulation across both cores for 60fps with audio no frameskip required 🚀#110
finger563 merged 16 commits into
mainfrom
feat/gen-dualcore

Conversation

@finger563

@finger563 finger563 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Description

Splits the Genesis (Mega Drive) emulator across both ESP32-S3 cores and tunes memory/cache so it runs at a full 60 fps with audio and no frameskip (previously ~44 fps with frameskip). Also fixes incorrect Doom audio and clears the PR's static-analysis findings.

Genesis dual-core (components/genesis)

  • Core 0 runs the 68000 + VDP; core 1 runs the sound unit (Z80 + YM2612 + SN76489), coordinated by a per-fGENESIS_DUAL_CORE in genesis_dualcore.h, with the single-core path retained as a known-good fallback.
  • Cross-core correctness: a lock-free SPSC queue for 68k→YM/PSG register writes, an atomic BUSREQ/RESET handshake (replacing the in-bus z80_sync), a per-line lockstep "leash" so the sound core never runs ahead of the 68k, and the Z80 V-interrupt held across vblank (with IAutoReset) so V-int-driven sound drivers don't miss it.

Performance/memory tuning

  • Instruction cache 16 KB → 32 KB (sdkconfig.defaults) — the m68k/Z80 interpreters were thrashing a 16 KB I-cache; this was the single biggest win.
  • Right-sized lfo_pm_table (int32_t[128832] → int16_t[128816], 131 KB → 32 KB) and prioritized M68K_RA

Static analysis

  • Fixed the cppcheck findings in code where appropriate (C-style → C++ casts, fopen null-checks, const paric, a dead store, and a corrected inline-suppression id), and narrowed suppressions.txt to a few documented, genuinely-unfixable cases.

Motivation and Context

The Genesis core was the most demanding emulator in the project and only ran ~44 fps, requiring frameskip and producing imperfect audio. Profiling showed the cost was spread across all subsystems (interpreters + VDP) serialized on one core and starved by a too-small instruction cache — no single micro-optimization could reach 60 fps. Splitting the sound subsystem onto the second core plus the cache bump removes that ceiling. Separately, Doom's audio was audibly wrong due to a
stereo/mono buffer-sizing bug, and the PR's static-analysis check was failing (largely due to a cppcheck vck ids).

How has this been tested?

  • Hardware: ESP32-S3-BOX-3.
  • Genesis: ran Sonic 1, Sonic 2, Sonic 3 & Knuckles, Aladdin, and Lion King — all at ~60 fps (work-rate ~60–70, capped to 60) with correct music and SFX. Per-subsystem timing instrumentation (temporary, since removed) was used to locate
    bottlenecks and to diagnose/fix a V-int-delivery bug that had silenced Sonic 2's music. The single-core pains as a fallback and was used as the reference.
  • Static analysis: verified locally with cppcheck (--enable=all --inconclusive, project suppressions.txt); all findings resolved.

Screenshots (if appropriate, e.g. schematic, board, console logs, lab pictures):

Console FPS/frame-time stats (representative, in-game):
SONIC THE HEDGEHOG: FPS: 69.9 Frame Time [min 9.5ms, avg 14.3ms, max 18.6ms]
ALADDIN: FPS: 75.7 Frame Time [min 9.0ms, avg 13.2ms, max 17.3ms]
SONIC 3 & KNUCKLES: FPS: 65.9 Frame Time [min 9.4ms, avg 15.2ms, max 23.0ms]

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update
  • Hardware (schematic, board, system design) change
  • Software change

Checklist:

  • My change requires a change to the documentation.
  • I have added / updated the documentation related to this change via either README or WIKI

Software

  • I have added tests to cover my changes.
  • I have updated the .github/workflows/build.yml file to add my new test to the automated cloud build
  • All new and existing tests passed.
  • My code follows the code style of this project.

@finger563 finger563 self-assigned this Jun 19, 2026
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

✅Static analysis result - no issues found! ✅

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

ESP-IDF Size Report for 'Esp Box Emu'

Metric Base PR Delta
FLASH 3,225,092 bytes (51.26%) 3,233,644 bytes (51.40%) 🔺 +8,552 bytes (+0.14%)
DRAM 268,739 bytes (78.63%) 178,459 bytes (52.22%) ⬇️ -90,280 bytes (-26.41%)
IRAM 16,384 bytes (100.00%) 0 bytes ⬇️ -16,384 bytes
RAM (DRAM+IRAM) 285,123 bytes 178,459 bytes ⬇️ -106,664 bytes (-27.39%)

FLASH uses app .bin size or json2 flash sum. RAM sums DRAM+IRAM via idf_size. Percentages shown when totals are available.
DRAM/IRAM usage does not include memory used by the heap allocator at runtime.
This report was generated by esp-idf-size-delta.

@finger563 finger563 merged commit 42ad36d into main Jun 20, 2026
3 checks passed
@finger563 finger563 deleted the feat/gen-dualcore branch June 20, 2026 00:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant