SuperMarioWorldRecomp

SuperMarioWorldRecomp brings Super Mario World to PC.

README

SuperMarioWorldRecomp

This recompilation is a byproduct of developing snesrecomp — the games are the proving ground, the framework is the goal. These are in-development previews, not finished ports — expect rough edges, and depth will keep landing over months, not days. My time for any one title is limited, so I ask for your patience. Contributions are welcome — testing, issues, and PRs to the game or framework all help and will accelerate this game's polish. More on the why at: Recomp + AI: 5 Months Later »

Static recompilation of Super Mario World (SNES) into native C, using the snesrecomp framework. This repo is the per-game side: the runtime, the recompiled C output, the per-game .cfg, and the build glue.

What "static recompilation" means here

The 65816 CPU code from the ROM is statically translated to C — every function the game runs on the SNES's main CPU is a real generated C function in src/gen/. The rest of the SNES is not recompiled — it's hardware. PPU rendering, the APU / SPC700 audio coprocessor, DMA and HDMA channels, hardware register I/O, and bank-mapping all run through a C reimplementation of the SNES hardware in snesrecomp/runner/src/snes/ — a LakeSnes-derived core (the same emulator family the snesrev reverse-engineered ports use), with individual algorithms credited to snes9x. This is the same model other static-recomp projects (N64Recomp, snesrev/zelda3, etc.) use: recompile the CPU, emulate the silicon. If you expected the PPU and APU to be recompiled too, they aren't — and a static recompiler can't recompile them because the SNES PPU has no instruction stream and the SPC700 is a separate processor with its own firmware that the cartridge uploads to a separate chip.

Current status: believed fully playable

Hand-verified end-to-end through:

  • Yoshi's Island (World 1) including Iggy's castle boss.
  • Donut Plains (World 2) end-to-end.
  • Vanilla Dome (World 3) in progress at time of writing.

No catastrophic visible regressions surfaced through these worlds. Two runtime tripwires (the M/X claim verifier and the async-cpu->m_flag/x_flag-write detector) are armed at boot and have not latched on the verified worlds. An off-rails event was captured in BufferScrollingTiles_Layer1_VerticalLevel_M1X1 during Donut Plains castle (bank-out-of-range pointer read; runtime mirrors the read to a safe location and gameplay continues) — see ISSUES.md for the bucketed capture and the offrails_get TCP query.

Worlds 4–7 and special content (Star Road, Special World) are not yet hand-verified but are expected to play similarly. If you hit a visible regression, please open an issue with a savestate and the offrails_get / mx_async_check_get JSON snapshots.

Active development; expect:

  • Some branches don't build; only main is guaranteed to build.
  • Internal docs (ISSUES.md, ENHANCEMENTS.md) assume context.
  • APIs and recompiler output change without notice.

See RELEASE.md for the latest release notes.

Quick start (pre-built release)

  1. Download the Windows ZIP or Linux AppImage from Releases. Extract the ZIP, or make the AppImage executable.
  2. Run SuperMarioWorldSNESRecomp.exe or the AppImage. On first launch a file picker asks for your legally-obtained Super Mario World (USA) ROM (.sfc / .smc). The path is remembered in rom.cfg next to the exe.
  3. Edit keybinds.ini (auto-generated next to the exe on first run) to remap keys, then restart.

The ROM is never redistributed — supply your own dump.

To play as Captain Falcon, enable Captain Falcon on the launcher's Mods page, select your Super Smash Bros. (USA) v1.0 ROM, and press Play. The included helper prepares Falcon's assets in your user cache on first use. No Python installation or environment setup is required.

Optional Lua scripting

The Windows/Linux packages include an opt-in localhost Lua server and a lua/ folder with a 100-fireballs-per-second hold-to-fire example. See lua/README.md for activation and controls. Nothing runs or listens during ordinary play. Source builds enable this with -DSNESRECOMP_ENABLE_LUA=ON; the framework option defaults OFF.

Widescreen

Enable SMW Adaptive Widescreen in the one-player launcher's Mods page. Its two controls are Aspect ratio (Fit to screen by default, plus fixed 4:3 through 100:9 choices) and Enemy spawn behavior (Screen-based by default, or Original 4:3 activation). The HUD anchors automatically: lives and bonus counters left, reserve item centered, TIME/coins/score right.

This experimental host renderer replaces the former PPU-expansion mod. Fit follows the live window or fullscreen aspect, with native pixel proportions and 224 lines; 100:9 renders 2134 columns without wrapping enemy coordinates. Title screens, the overworld, transitions, and unsupported PPU modes retain their native view. The original enemy-slot pool still limits how many enemies can be active across very wide views.

See the renderer guide for building, isolated playtesting, architecture, checks, and current limitations. Old Widescreen and WidescreenHud INI fields no longer control this mod.

Simultaneous co-op build

The repository also produces a separate SuperMarioWorldCoopSNESRecomp build. It uses the simultaneous co-op gameplay patch while keeping the normal legal ROM flow: select an untouched Super Mario World (USA) ROM in the launcher or pass it on the command line.

On first use, the executable verifies the stock ROM and applies the bundled IPS delta. The IPS contains the co-op hack's changed bytes, but not a complete ROM. The generated file is written beside the executable as <stock-rom-name>.coop.sfc; that generated co-op ROM is what the runtime loads. Subsequent launches reuse it after verifying its CRC. Both headerless .sfc dumps and 512-byte-headered .smc dumps are accepted as input. To force a clean repatch, delete the generated .coop.sfc file.

Player 1 and Player 2 are active simultaneously in levels. Connect two SDL game controllers, or configure the [Player1] and [Player2] keyboard bindings in keybinds.ini. The stock ROM and generated .coop.sfc remain local and must not be redistributed.

Widescreen is currently disabled in the co-op build, and its launcher omits the aspect-ratio control. Co-op always runs in Standard (4:3) even if an older configuration or SNESRECOMP_WIDESCREEN requests another mode. The experimental IPS-specific hooks remain in the source for future work, but extended terrain streaming is not yet reliable during normal scrolling.

Network co-op

The co-op executable supports two-player delay-sync netplay through snesrecomp's recomp-net integration and recomp-ui. Both players must use the same build and a matching verified SMW (USA) ROM.

  1. Start SuperMarioWorldCoopSNESRecomp and open Netplay in the launcher. The first visit asks for a player name and saves it for later launches.
  2. Choose Host Lobby. Online publishes the room through the configured lobby server; LAN / Direct IP advertises it directly on the local network. Create immediately opens the waiting room.
  3. The guest joins the matching Super Mario World Co-op room. Once both seats are occupied, the host selects Play; the guest does not need a separate ready action.
  4. The host controls Mario (network slot 1) and the guest controls Luigi (network slot 2). Each machine uses its Player 1 keyboard/controller by default, so the guest does not need separate Player 2 bindings.

Closing the game or pressing Escape during a network match returns both players to the room for a rematch. Use Leave Lobby to disconnect instead.

The simulation waits for confirmed inputs before every frame. Turbo, pause, and local reset are disabled during a session; save/load synchronization is host-authoritative. LAN uses UDP directly. Internet games may require a build configured with -DSNESRECOMP_NET_ICE=ON, which includes libjuice-based NAT traversal, when the peers cannot reach each other directly.

For a launcher-free loopback or CI smoke test, start two instances with the same session ID and opposite ports:

# Host
$env:SNES_NETPLAY='1'; $env:SNES_NET_SLOT='0'
$env:SNES_NET_SESSION_ID='4242'; $env:SNES_NET_TRANSPORT='lan'
$env:SNES_NET_BIND='0.0.0.0:7777'; $env:SNES_NET_PEER='127.0.0.1:7778'
$env:SNES_NET_TEST_TICKS='600'
.\SuperMarioWorldCoopSNESRecomp.exe .\smw.sfc

# Guest (in another terminal)
$env:SNES_NETPLAY='1'; $env:SNES_NET_SLOT='1'
$env:SNES_NET_SESSION_ID='4242'; $env:SNES_NET_TRANSPORT='lan'
$env:SNES_NET_BIND='0.0.0.0:7778'; $env:SNES_NET_PEER='127.0.0.1:7777'
$env:SNES_NET_TEST_TICKS='600'
.\SuperMarioWorldCoopSNESRecomp.exe .\smw.sfc
Co-op hack attribution

This build distributes an IPS delta for Super Mario World - 2 Player Simultaneous Co-op Hack. Original hack credits:

  • Noobish Noobsicle - creator of the original SMW co-op hack
  • Bloony Fox and NesDraug - developed it into the full hack used here

Source and original credits: Romhack Plaza - Super Mario World - 2 Player Simultaneous Co-op Hack. This recompilation project is not affiliated with or endorsed by the hack authors.

Controls (default keybinds.ini)

SNES buttonDefault key
D-PadArrow keys
AX
BZ
XS
YA
LC
RV
StartEnter
SelectRight Shift

Player 2 is unbound by default — fill in keys in keybinds.ini to enable a second keyboard player. In the co-op build, the two bindings drive Mario and Luigi at the same time rather than taking turns.

Xbox / PlayStation / Switch Pro controllers are auto-detected via SDL_GameController (XInput on Windows). Plug it in before launching, or hot-plug after. Default Xbox mapping is position-true: the physical button position matches a SNES pad — so Xbox A (south face) sends SNES B, Xbox B (east face) sends SNES A. To rebind, edit the [GamepadMap] section of config.ini (auto-generated next to the exe on first run); the recognized names and the full mapping table are in CONTROLLER.md.

System shortcuts (configured in config.ini's [KeyMap] section):

ActionDefault
Save state 1-10Shift+F1..F10
Load state 1-10F1..F10
Toggle pauseP
ResetCtrl+R
Toggle fullscreenAlt+Enter
Turbo (fast-forward)Tab
Toggle rendererR
Display perfF

Building from source

Prerequisites: Windows 10+, Visual Studio 2022 (with C++ desktop workload), Python 3.9+ on PATH, and rustup for regeneration.

git clone --recurse-submodules https://github.com/mstan/SuperMarioWorldRecomp
cd SuperMarioWorldRecomp

Regenerate the desired variant from your legally obtained stock ROM, then build it. The generated C is intentionally untracked:

# Normal 1P build (the default)
bash tools/regen.sh --stock
msbuild smw.sln /p:Configuration=Production /p:Platform=x64 /m

# Simultaneous co-op build
bash tools/regen.sh --coop
msbuild smw.sln /p:Configuration=CoopProduction /p:Platform=x64 /m

The normal configuration remains smw.exe; the additive configuration creates SuperMarioWorldCoopSNESRecomp.exe in its own output directory and copies smw_coop.ips beside it. CMake builds the normal target by default; configure with -DSMW_BUILD_COOP=ON to make both targets available in one build tree.

The netplay-enabled co-op target uses CMake so it can link recomp-net. A sibling engine worktree can be selected without replacing the checked-in submodule:

$engine = 'F:\path\to\snesrecomp-worktree'
$ui = 'F:\path\to\recomp-ui-worktree'
$sdl3 = 'F:\path\to\SDL3'
$env:SNESRECOMP_ROOT = $engine
bash tools/regen.sh --coop --no-tests
cmake -S . -B build-netplay -DSMW_BUILD_COOP=ON `
  -DSNESRECOMP_ROOT="$engine" -DRECOMP_UI_ROOT="$ui" `
  -DCMAKE_PREFIX_PATH="$sdl3" `
  -DSMW_NETPLAY_ICE=ON
cmake --build build-netplay --config Release `
  --target SuperMarioWorldCoopSNESRecomp --parallel

SDL3 is the default desktop backend. To build the maintained compatibility fallback, configure a separate tree with -DSNESRECOMP_SDL_BACKEND=SDL2.

Regenerating the recompiled C (contributors)

If you change anything under recomp/bank_*.cfg, the snesrecomp framework, or otherwise need to re-run the recompiler:

  1. Drop a legally-obtained smw.sfc at the repo root (.gitignore excludes it).
  2. Run bash tools/regen.sh --stock for the normal build and/or bash tools/regen.sh --coop for co-op. Stock emits to src/gen/ from the vanilla SMW (USA) ROM. Co-op applies the bundled IPS to a throwaway verified ROM, layers the small CFG fragments in recomp/coop/, and emits independently to src/gen-coop/. It builds and requires the fast native analyzer by default; set SNESRECOMP_ANALYSIS_BACKEND=python only to use the slower reference path.
  3. Rebuild as above.

(Build and run instructions are not yet stable — see scripts under tools/ and notes in docs/ for the current shape, but expect them to drift.)

MSU-1 audio

The normal 1P build supports CD-quality MSU-1 streaming music using a stock SMW (USA) ROM. Regeneration no longer applies Conn's audio-only "SMW MSU-1" patch; the preloaded MSU-1 Audio Mods package activates trusted host-side code that observes SMW music commands and drives the runner's MSU-1 device directly. At runtime, no pack means authentic SPC audio; a matching PCM pack plus the MSU-1 Audio mod means streamed music. Packs for SMW MSU+ or SMW MSU-1 Plus Ultra are not interchangeable with this audio-only track map. Full credit and pack details are in recomp/msu1/ATTRIBUTION.md.

MSU-1 is disabled in the simultaneous co-op build for now.

Repo layout

  • src/ — runtime C (CPU state, runtime helpers, hand-written bodies for things the framework doesn't yet recompile).
  • src/gen/ — recompiler output (do not hand-edit).
  • src/gen-coop/ — separate co-op recompiler output (do not hand-edit).
  • recomp/ — per-bank .cfg files describing what the framework cannot yet derive from the ROM (data regions, calling conventions, rare hints).
  • recomp/coop/ — co-op CFG overlays, distributed IPS, and attribution.
  • snesrecomp/ — pinned framework submodule.
  • tools/ — build, regen, audit, and triage scripts.
  • docs/ — design / debugging notes (internal-facing, may be stale).
  • third_party/ — vendored deps with their own licenses.

Acknowledgements

This port did not start from scratch. It stands on prior reverse-engineering and emulation work, and we're grateful for it:

  • IsoFrieze/SMWDisX — the Super Mario World disassembly used as the basis for this port. SMWDisX is the source of the symbol names, the RAM/variable map, and the per-bank function boundaries, and it serves as the differential conformance oracle for the recompiled output (see tools/smwdisx_compare.py and the vendored SMWDisX/ clone). SMWDisX in turn credits mikeyk's original 2013 disassembly and loveemu's SPC700 sound-engine work.
  • snesrev (snesrev/smw, snesrev/zelda3) — the runner and surrounding ecosystem were heavily based on the snesrev reverse-engineered ports: the "port the CPU code to C, emulate the rest of the silicon, verify against a reference emulator" model, the C runtime structure, and the SPC-image audio path.
  • The C SNES hardware core under snesrecomp/runner/src/snes/ derives from LakeSnes (elzo-d), the emulator snesrev's projects vendor, with algorithms credited inline to snes9x.

See the snesrecomp framework README for the full framework-side attribution.

Discord

https://discord.gg/S4MvUGQFwd

License

PolyForm Noncommercial 1.0.0. See LICENSE. Code in this repo is original except where noted in Acknowledgements above; vendored dependencies under third_party/ (and the SMWDisX/ disassembly clone) retain their own licenses.

The SMW ROM and any data extracted from it are not in this repo and are not licensed for redistribution.


R.A.I.D. — Retro AI Development · a Discord for AI-assisted retro reverse-engineering, decomp & recomp

Join the Retro AI Development (R.A.I.D.) Discord