Gaming [WIP] Tatsunoko vs. Capcom: Ultimate All-Stars on macOS Apple Silicon via static ARM64 recompilation

  • Thread starter Thread starter Hardy_Heron
  • Start date Start date
  • Views Views 247
  • Replies Replies 1
  • Likes Likes 1

Hardy_Heron

Well-Known Member
Newcomer
Joined
Mar 6, 2017
Messages
65
Reaction score
9
Trophies
0
Age
51
Location
Valparaíso
Website
altf4.cl
XP
289
Country
Chile


Hi everyone,​


I’ve been working on a personal experiment with Tatsunoko vs. Capcom: Ultimate All-Stars on Wii, and I wanted to share the current state of the project because I think it may be interesting for people here who are into emulation, reverse engineering, static recompilation and preservation.

My goal was not simply to run the game through Dolphin.

What I wanted was to take my own legal backup of the game, extract the executable, statically recompile the PowerPC code to ARM64, and build a portable macOS application around it for Apple Silicon Macs.

At this point I have a working portable build that runs the game at roughly 60 FPS on my Mac mini M4, using Metal and an Xbox controller.

The final result behaves much more like a dedicated macOS application than a traditional emulator setup.



What I used​

The main tools involved were:

  • DolRecomp
  • ModernGekko
  • Dolphin code used through the ModernGekko runtime
  • LLVM 20
  • CMake
  • Ninja
  • Git
  • Homebrew
  • Apple Clang
  • macOS tools such as codesign, install_name_tool, otool, iconutil, etc.
The source game is my own legal USA backup of Tatsunoko vs. Capcom: Ultimate All-Stars.

The Wii executable is the usual:

main.dol
The important part of the process was recompiling that executable into an ARM64 dylib.

DolRecomp successfully processed the game with very good coverage. The recompilation report showed:

840838 instructions
1650 embedded data entries
unknown: 0
native: 100%
fallback: 0
The resulting module is an ARM64 Mach-O dylib loaded by the ModernGekko runtime.



What the final build looks like​

I ended up creating a fully portable folder like this:

Tatsunoko vs Capcom Portable/
├── Tatsunoko vs Capcom.app
└── UserData/
Inside the app bundle I packaged:

moderngekko-run
ARM64 recompiled game module
game data
Dolphin / ModernGekko runtime files
controller profile
lz4
zstd
native ARM64 launcher
The launcher resolves all paths relative to the application itself.

That means the build no longer depends on my development directories, username, Homebrew installation or SSD name.

I can move the entire folder to another external drive and run it from there.

I tested the portable build from an ExFAT SSD and it launches correctly.



Main technical problems I encountered​

This was definitely not a case of “compile and run”.

There were several problems along the way.

1. LLVM / Mach-O incompatibility​

The DolRecomp LLVM backend was trying to assign functions to sections such as:

.text.unlikely.*
This works in other object formats but caused problems when generating Mach-O binaries on macOS.

I ended up applying a small Apple-specific guard so that those sections are not assigned on macOS.

After that, the LLVM backend built correctly.



2. GXRuntime / ModernGekko ABI mismatch​

There was also a mismatch between the CPU state structures expected by ModernGekko and the version of GXRuntime included in the project.

I had to update the runtime ABI and add the missing fields used by the current runtime, including:

cycle_budget
There were also changes related to native-region queries.

Without matching these structures correctly, the recompiled code and the runtime were not communicating properly.



3. Native-region query problem​

This was probably the most important issue.

The recompiled executable performs a special host call to ask the runtime whether a memory region is handled by native recompiled code.

ModernGekko was not handling this query correctly.

The result was that execution became effectively stuck around the game entry point:

0x800062F0
I added handling for the special native-region query host call.

Conceptually, the runtime now receives the address being queried and checks whether that address belongs to a loaded native module.

Once that was fixed, the game started progressing properly instead of looping at startup.

That was the point where the project really started becoming viable.



4. libusb issue on macOS​

I also hit a crash involving libusb.

The problematic code path was related to pipe2.

On macOS the runtime could end up referencing pipe2 in a way that resulted in a null-function call.

I added an Apple-specific workaround so libusb uses the more traditional:

pipe + fcntl
path instead.

That removed another startup crash.



5. Bluetooth HLE crash​

The next major issue appeared in the Bluetooth emulation layer.

Some control messages were arriving with:

length = 0
Later code performed arithmetic equivalent to:

length - 3
which obviously underflowed and resulted in an invalid size.

For debugging I added a temporary fallback that uses the actual IO buffer size when the control-message length is zero.

Something roughly equivalent to:

if (ctrl.length == 0 && io_size > 0)
ctrl.length = io_size;
This made the game boot and run successfully.

However, I consider this a workaround, not a real fix.

One of the things I would really like feedback on is:

why are all of these Bluetooth control messages arriving with wLength / length set to zero in this setup?

The fallback works, but I would much rather understand the root cause.



Controller configuration​

The controller side also turned out to be interesting.

ModernGekko was initially creating a GameCube controller configuration that was not useful for this game.

I disabled the GC controller ports and configured the runtime around a sideways Wii Remote profile.

I tested several physical controllers.

The best result so far has been with an Xbox controller.

With that configuration I get approximately:

59 - 61 FPS
and gameplay feels stable.

I also tested a Switch Pro controller and a Machenike G5 Pro.

For reasons I have not yet fully investigated, those configurations caused the framerate to fluctuate much more aggressively, sometimes dropping into the 20s and 30s.

So for the current portable build I am treating the Xbox controller as the reference configuration.

I would also be interested to hear if anyone has seen similar performance differences related to SDL controller devices or polling behavior.



Making it truly portable​

Once the game itself worked, I wanted to remove my development environment from the equation.

moderngekko-run originally depended on Homebrew paths such as:

/opt/homebrew/opt/lz4/lib/liblz4.1.dylib
/opt/homebrew/opt/zstd/lib/libzstd.1.dylib
I copied those libraries into the app bundle and rewrote the dependencies to use:

@executable_path
The result is that the final build no longer needs Homebrew installed.

It also does not require Dolphin or ModernGekko to be installed separately.

The launcher itself is a small native ARM64 program that locates:

Runtime
Game
Module
UserData
relative to its own bundle path.

This means I can copy the folder to another SSD without changing any paths.



Current result​

Right now the build:

  • runs on Apple Silicon
  • is ARM64
  • uses Metal
  • runs close to 60 FPS
  • works well with Xbox controllers
  • does not require Homebrew
  • does not require Dolphin installed
  • does not require ModernGekko installed
  • does not require Rosetta
  • can run directly from an external SSD
  • behaves like a normal macOS .app
The target is currently:

macOS 13+
Apple Silicon only
M1 / M2 / M3 / M4 and future compatible ARM64 Macs


Is this a native port?​

I would not call it a pure native port.

I also would not describe it as normal emulation.

The main game executable has been statically recompiled from PowerPC to ARM64, but ModernGekko / Dolphin still provide the environment the game expects:

  • Wii memory behavior
  • IOS services
  • graphics
  • audio
  • input
  • USB
  • Bluetooth
  • other hardware abstractions
So the most accurate description, at least in my view, would be:

a static ARM64 recompilation compatibility port using a Dolphin-derived HLE runtime
It sits somewhere between a conventional emulator setup and a traditional source-code port.



Why I think this approach is interesting​

The most obvious advantage is not necessarily raw performance.

Dolphin is already extremely optimized.

What I find interesting is the possibility of creating game-specific compatibility builds.

Once the executable is statically recompiled, it becomes possible to think about things like:

  • game-specific patches
  • native ARM64 optimizations
  • cleaner macOS integration
  • standalone .app packages
  • controller profiles designed specifically for one game
  • custom resolutions
  • widescreen fixes
  • frame pacing improvements
  • reducing runtime overhead
  • replacing more emulated/HLE paths with native implementations
  • eventually identifying which parts of Dolphin are actually necessary for a specific title
For me, that is the really interesting part.

Instead of asking:

“How well does this emulator run thousands of Wii games?”
the question becomes:

“How far can we push compatibility and native execution for this one specific game?”


Things I still want to investigate​

There are several areas I consider unfinished:

  1. Understand the real cause of the Bluetooth control-message length issue.
  2. Investigate the controller-dependent performance differences.
  3. Review the self-modifying-code report from DolRecomp.
    The game has several possible patching regions, and although the runtime currently reports no SMC failure during normal execution, I do not want to assume those regions are harmless.
  4. Reduce the size of the portable package.
  5. Test on more Apple Silicon machines, especially M1 and M2 systems.
  6. Test different macOS versions.
  7. Clean up the temporary diagnostic patches.
  8. Investigate whether more of the Dolphin runtime can eventually be removed or specialized specifically for TvC.


Looking for feedback / contributors​

I’m posting this because I would really appreciate input from people who understand Dolphin internals, Wii IOS, Bluetooth HLE, PowerPC recompilation, LLVM or static recompilation projects.

In particular, I would love opinions on:

  • the Bluetooth length == 0 behavior
  • the native-region host-call implementation
  • whether the SMC regions in TvC are likely to become relevant later
  • the controller-related performance differences
  • whether there are better approaches for packaging the runtime on macOS
  • possible ways to reduce the amount of Dolphin code needed for a single-game build
I’m still learning a lot of this as I go.

I do not come from a professional software-development background, so part of the project has been learning how all of these pieces fit together.

I built this with a lot of experimentation, log analysis and assistance from ChatGPT, especially for understanding crashes, preparing small patches and navigating the ModernGekko / DolRecomp codebase.

If anyone here wants to help investigate specific issues, suggest cleaner fixes, or experiment with other Wii titles using the same approach, I would be very interested in collaborating.

Even just technical criticism would be useful.

I’m especially interested in hearing from anyone who has experience with:

  • Dolphin internals
  • static recompilation
  • Wii hardware / IOS
  • ARM64
  • LLVM
  • macOS Mach-O binaries
The project is already playable, but I think there is a lot more potential here.



Legal note: I am working exclusively from my own legally obtained copy and personal backup of Tatsunoko vs. Capcom: Ultimate All-Stars. I am not distributing the game, ROMs, extracted assets or other proprietary game content. Any public release of the technical work would need to separate patches, source code, configuration and open-source components from copyrighted game data.
 
Last edited by Hardy_Heron,
  • Like
Reactions: Disorarara
Tatsunoko vs. Capcom: Ultimate All-Stars
Wii → ARM64 macOS progress update
Static recompilation, portable Apple Silicon build and the new TvC Settings app


Hi everyone,

I would like to share a substantial update to my personal Tatsunoko vs. Capcom: Ultimate All-Stars project for Apple Silicon Macs. Since my original post, the project has progressed from an initial ARM64 bring-up into a validated portable build, followed by a dedicated native SwiftUI configuration app.

The current stable configuration app is TvC Settings 0.6.3. It manages video options, pixel-locked CRT shaders, Xbox/Classic Controller mappings, saved games and safe game launching/closing without modifying the recompiled game executable.

Important technical clarification: this is a static recompilation project, not a traditional source-level port and not a full decompilation. The Wii PowerPC game code is translated into native ARM64 code, while the native ModernGekko runtime provides the platform, graphics, audio and system services required by the game.

1. Initial ARM64 bring-up

The first stage was identifying and processing the USA Rev 0 build of the game:

  • Game ID: STKE08
  • Original platform: Nintendo Wii / PowerPC
  • main.dol entry point: 0x800062F0
  • Recompiler environment: DolRecomp on Apple Silicon with LLVM 20.1.8 arm64
  • Validation: 19/19 tests passed
  • Instructions processed: 840,838
  • Unknown instructions: 0
  • Generated object chunks: 6,583
  • Resulting module: gSTKE08_recomp.dylib, approximately 219 MB

This produced a native ARM64 game-code module. ModernGekko was then built natively for macOS with LLVM, Metal graphics and Cubeb audio, allowing the game to run in a native macOS window on Apple Silicon.

2. Portable macOS application

After the first successful execution, the next goal was to remove machine-specific paths and external dependencies. The project was converted into a portable folder with relative paths:

Code:
Tatsunoko vs Capcom Portable/
├── Tatsunoko vs Capcom.app
├── TvC Settings.app
└── UserData/

The current portable build includes the required runtime, system files and recompiled module. LZ4 and Zstandard support are bundled, so the portable does not require Homebrew, Rosetta, a separate Dolphin installation or a separate ModernGekko installation.

This build was validated directly from an external ExFAT SSD. It uses Metal, supports an Xbox Wireless Controller and runs at approximately 60 FPS in the tested configuration. The app bundle also received its own icon and a valid local signature. Because this is an independently signed development build, macOS may still require using right-click → Open on first launch.

3. Evolution of TvC Settings

Version 0.1 – first graphical configurator

  • Independent native SwiftUI app.
  • Internal-resolution selection.
  • Metal kept as the rendering backend.
  • Controller detection.
  • Automatic backup of config.ini before writing changes.
  • Direct PLAY button.
  • No changes to game speed, FPS or timing.

Version 0.3 – video and CRT expansion

  • Added native Wii 1× rendering at 640×528/EFB.
  • Added fullscreen control.
  • Added CRT Off, Soft Scanlines and Strong Scanlines.
  • Introduced pixel-locked scanline shaders designed to remain regular at 1080p, 1440p, 4K and 5K.
  • Preserved existing configuration instead of rebuilding UserData from scratch.

Version 0.3.1 – portability and Gatekeeper testing

This revision focused on copying the app safely to the portable SSD, verifying the ARM64 binary, re-signing the bundle and testing macOS quarantine/Gatekeeper behaviour. It confirmed that an ad-hoc signed development build can still require manual approval through right-click → Open.

Version 0.6.1 – complete functional base

This became the first complete settings application and introduced the full multi-section interface:

  • General video and CRT configuration.
  • Xbox controller panel with visual button pictograms.
  • Wiimote Horizontal profile support.
  • STKE08 save-game manager.
  • Direct game launch.
  • Safe game closing, with a separate manual force-close option only when required.

Several experimental builds were tested after this point. A simplified 1.1 branch removed working screens and was treated as a regression, so it was discarded. Development returned to the validated 0.6.1 codebase instead of continuing from that branch.

Version 0.6.3 – current stable version

Version 0.6.3 is the latest validated stable base and expands the controller system substantially:

  • The Classic Controller · TvC profile is now fully remappable.
  • Xbox physical buttons and Classic Controller actions can be reassigned directly in the interface.
  • The controller infographic updates immediately when a mapping changes.
  • Button pictograms make the current layout easier to understand.
  • Custom Classic mappings are detected when TvC Settings is reopened.
  • A single button restores the recommended layout that was validated in the real port.
  • The existing customizable Wiimote Horizontal profile remains available.
  • The General, Saves, pixel-locked CRT and safe-close features from 0.6.1 are preserved.

TvC Settings 0.6.3 – General / Video / CRT


Xbox / Classic Controller remapping with dynamic infographic


STKE08 save manager

4. Recommended controller layout

Code:
Xbox A       → Classic A     → Heavy attack / Confirm
Xbox B       → Classic B     → Partner / Cancel
Xbox X       → Classic Y     → Light attack
Xbox Y       → Classic X     → Medium attack
LB           → Classic L     → Heavy attack
RB           → Classic R     → Light + Medium + Heavy
View         → Classic −     → Taunt
Menu         → Classic +     → Pause
Xbox / Guide → Classic HOME  → HOME Menu
D-Pad        → Movement
Left stick   → Movement

The face buttons, shoulders, triggers, View, Menu and Guide buttons can be remapped. The D-Pad and left stick remain dedicated to movement.

5. Save-game management and safety

TvC Settings detects the active STKE08 save at:

Code:
UserData/Wii/title/00010000/53544b45

The app can create a manual backup, import a compatible save profile and validate its structure before activation. A valid save must contain at least:

Code:
content/title.tmd
data/backup.bin
data/banner.bin

Activation uses a staging process, creates an automatic backup first and performs an automatic rollback if replacement cannot be completed correctly.

The settings app may back up or modify config.ini, GFX.ini, WiimoteNew.ini, shaders and managed save profiles. It does not modify Tatsunoko vs Capcom.app, the ARM64 game executable or GCPadNew.ini when working with the Classic Controller profile.

6. Current requirements

  • Apple Silicon Mac: M1, M2, M3, M4 or later ARM64-compatible model.
  • macOS Ventura 13 or later.
  • Approximately 3 GB of free space.
  • Xbox Wireless Controller recommended; this is the controller used for validation.
  • Tatsunoko vs Capcom.app, TvC Settings.app and UserData must remain together in the portable folder.

7. Current status

  • ARM64 recompilation: working.
  • Apple Silicon portable: validated.
  • Metal rendering and audio: working in the tested build.
  • Xbox controller: working with editable Classic and Wiimote Horizontal profiles.
  • Video and pixel-locked CRT modes: working.
  • Save manager with backup/rollback: working.
  • Current stable configuration app: TvC Settings 0.6.3.

8. Legal and distribution note

This is a personal, non-commercial compatibility and preservation project. It requires a legally obtained personal backup of Tatsunoko vs. Capcom: Ultimate All-Stars. No Nintendo, Capcom or Tatsunoko game files, characters, music, graphics or other proprietary assets are being offered or distributed.

If the project is shared publicly, the intended distribution is limited to original code, scripts, configuration files, patches, documentation and redistributable open-source components under their respective licences. The original game data must be supplied by the user from their own legal copy.

The portable build and TvC Settings were created and configured by Me, with technical and documentation assistance from ChatGPT. ModernGekko, Dolphin and all third-party components retain their original licences.

Next steps

The 0.6.3 codebase is now the stable foundation for future work. Further changes will be tested on an isolated copy before replacing the validated portable build. My priorities are continued compatibility testing, interface refinement and documenting a legal, reproducible setup process.

Thanks for reading. Feedback from the GBAtemp community is welcome, especially regarding Apple Silicon testing, controller behaviour and reproducible packaging.
 

Site & Scene News