Tomba!
Sobre el proyecto
Tomba! es un videojuego de plataformas, acción y aventura creado por Whoopee Camp Co. Ltd. y publicado por Sony Computer Entertainment para la consola de videojuego PlayStation. Fue lanzado en 1997 para Japón y en 1998 para Norteamérica y la región PAL. Tombi! también contó con una secuela titulada Tombi! 2: The Evil Swine Return en 1999. También ha sido lanzado en PlayStation Network por MonkeyPaw Games. La saga es fue idea del creador de juegosTokuro Fujiwara, quien creó los videojuegos Ghosts'n Goblins y Mega Man.
2 versiones de Tomba!
Estás viendo: Tomba!
Información oficial del proyecto
Tomba! PSX Decompilation
<div align="center"> <img src="https://github.com/hansbonini/psx_tomba/blob/main/docs/assets/logo.png?raw=true" alt="Tomba! Logo" width="400"/> </div>A decompilation of Tomba! for the original PlayStation, also released as Ore! Tomba in Japan and Tombi! in Europe. The goal is C source code that compiles back into byte-identical executables for every retail release. That source code supports:
- 🔧 Modding: patches, translations and enhancements built on real source code
- 📖 Study: how a late-90s PlayStation game was programmed
- 🌍 Preservation: keeping the game's code understandable for the future
🌍 Supported Versions
All four releases build from the same sources and are checked byte for byte.
| Region | Serial | VERSION | Executables | SHA1 of the main executable |
|---|---|---|---|---|
| 🇺🇸 NTSC-U | SCUS-94236 | scus_942.36 (default) | SCUS_942.36 and the code overlays SYSTEM/OPTSUB00.BIN, X00–X18 | 81cbc79f0230aeb4252e058039f47ac95a777f5a |
| 🇯🇵 NTSC-J | SLPS-01144 | slps_011.44 | SLPS_011.44 | 07d577698ad31ec1a69b9d7b80a7c3f90b650888 |
| 🇪🇺 PAL (En/Fr/De/It/Nl) | SCES-01330 | sces_013.30 | SCES_013.30 and EXE/MAIN0.EXE–MAIN8.EXE | 1d98c6595a49bd8063c906221df1eaa854964cb1 |
| 🇪🇺 PAL (En/Es/Pt/Sv/Da) | SCES-01331 | sces_013.31 | SCES_013.31 and EXE/MAIN0.EXE–MAIN8.EXE | f6c383514e5d8367d2eed06400315cf6dd57ef6b |
On the European discs, SCES_013.3x is only the language menu. The game itself is EXE/MAINn.EXE,
with one executable per language. The checksums of every file are in config/<VERSION>/checksum.sha.
US is the reference release: functions are decompiled there first. The other releases reuse every object that is the same in their executable. See How the versions share code.
📊 Progress
Live progress is tracked on decomp.dev from the objdiff
report that CI publishes on every push to main.
| Scope (US) | Matched code |
|---|---|
| Overall, overlays included | 38.3% |
Main game code (main) | 78.0% |
Psy-Q SDK (sdk) | 88.0% |
Shared overlay engine and X00 area (x00) | 77.0% |
Local report from 2026-10-14. The badges are live; this table will drift.
Matched code is weighted by bytes, so a 1200-byte state machine counts for more than a three-line accessor. The other Xnn area modules have barely started, which is why the overall number is far below the main executable's.
Note: the game links PSY-Q libraries from mixed SDK versions (for example libpad 4.2 alongside 4.3), so signature matching is done per object, not per SDK release.
🛠️ Toolchain
| Component | Version / Source | Role |
|---|---|---|
| splat | 0.35.2 (pinned) | Splitting and disassembly |
| spimdisasm | 1.36.0 (pinned) | MIPS disassembly backend |
gcc 2.7.2-psx | tools/gcc-2.7.2-psx/ | Original-era C compiler (cc1) |
| maspsx | tools/maspsx/ | ASPSX 2.56 assembler emulation |
binutils-mips-linux-gnu | distro package | Assembler and linker |
| objdiff | tools/objdiff/ | Per-object diffing and progress reports |
| decomp-permuter | make permuter-setup | Search for near-matches |
| m2c | tools/m2c/ | First-pass assembly-to-C |
| mkpsxiso | tools/mkpsxiso/ | Disc extraction (dumpsxiso) and rebuild |
| armips | tools/armips/armips (not bundled) | Standalone patches in patch/ |
splat and spimdisasm are pinned on purpose. The build assembles the code they generate, and their labels and rodata output change between releases, so an unpinned upgrade breaks the link in ways that look nothing like a code error.
📁 Project Structure
PSX_TOMBA/
├── src/ # C sources shared by every release
│ ├── main/ # game code
│ ├── psyq/ # PSY-Q SDK
│ └── overlays/ # code overlays (US): shared engine + area modules
├── include/ # headers (game.h, common.h, psyq/)
├── config/<VERSION>/ # splat configs and checksums of each release
├── symbols/<VERSION>/ # symbol tables of each release
├── asm/<VERSION>/ # disassembly generated by splat (not in git)
│ ├── nonmatchings/ # functions still in assembly, used by INCLUDE_ASM
│ └── matchings/ # functions already in C, for reference
├── linker/<VERSION>/ # generated linker scripts (not in git)
├── build/<VERSION>/ # objects of each release (not in git)
├── build/out/iso/ # rebuilt executables
├── iso/<VERSION>/ # extracted disc of each release (not in git)
├── patch/ # standalone armips patches (debug menus)
├── i18n/ # translation data
├── docs/ # technical documentation
├── tools/ # toolchain and project scripts
└── *.xml # mkpsxiso disc layouts
🚀 Getting Started
Prerequisites
- Linux or WSL: the bundled
cc1is a 32-bit Linux ELF binary - Python 3.8+ and Make
binutils-mips-linux-gnuandcpp-mips-linux-gnu
Setup
-
Clone with submodules
git clone --recurse-submodules https://github.com/hansbonini/psx_tomba.git cd psx_tomba -
Install the toolchain
sudo apt-get install make binutils-mips-linux-gnu cpp-mips-linux-gnu python3 -m pip install splat64[mips]==0.35.2 spimdisasm==1.36.0Pin both. splat only asks for
spimdisasm>=1.36.0,<2.0.0, so pip would otherwise pull a newer backend that produces different labels. -
Extract your disc
Use a disc you legally own. Extract it with
dumpsxiso(from mkpsxiso) intoiso/<VERSION>. Pass the.binimage, not the.cue:dumpsxiso -x iso/scus_942.36 -s SCUS_94236.xml "Tomba! (USA).bin"Check the main executable against the SHA1 in the table above. Every offset in the project assumes those exact builds.
-
Build and check
make generate # splat: disassembly and linker scripts make check # build and compare with config/<VERSION>/checksum.shaEvery target takes
VERSION, and US is the default:make VERSION=slps_011.44 generate make VERSION=slps_011.44 checkEvery
OKin themake checkoutput means that file is byte-identical to the original.
Make Targets
| Target | Purpose |
|---|---|
make generate | Run splat for every executable of VERSION |
make build / make check | Build; build and verify the checksums |
make report | Re-split, build the objdiff baseline and write build/<VERSION>/progress.json |
make regenerate | Remove the asm, linker scripts and build of VERSION, then run splat again |
make clean / make reset | Remove the build of VERSION; also its asm and linker scripts |
make permuter-import FUNC=… SRC=… / make permuter-run FUNC=… | Search for near-matches with decomp-permuter |
make patch_debug_sfx etc. | Build the standalone debug patches in patch/ |
If you edit a header such as
game.h,makedoes not rebuild the objects that include it. Removebuild/<VERSION>/srcbefore measuring.
🔀 How the Versions Share Code
There is one src/ for all releases. Each release has its own splat config, symbol tables, asm and
build folder:
-
Only the asm differs per release.
INCLUDE_ASMpaths are relative (INCLUDE_ASM("nonmatchings/main/game/event", func)). The assembler looks them up in the asm folder of the executable being built (asm/<VERSION>, orasm/<VERSION>/exe/mainNfor a European MAIN). -
The C keeps the US names. Each executable of another release gets
symbols/<VERSION>/<name>_symbol_addrs.txt, which places the US names at that executable's addresses. Names splat makes up there carry the serial as a suffix (D_80012345_slps01144), so they never clash with the US ones. -
A function that differs in a release is kept in assembly there. The
#ifuses one macro per serial, which the Makefile defines fromVERSION:#if defined(VERSION_SLPS_01144) || defined(VERSION_SCES_01330) INCLUDE_ASM("nonmatchings/main/render/camera", loadSpawnPosition); #else void loadSpawnPosition(void) { ... } #endifThe macros are
VERSION_SCUS_94236,VERSION_SLPS_01144,VERSION_SCES_01330andVERSION_SCES_01331.
These files are generated, not edited by hand. Two scripts produce them:
| Script | What it does |
|---|---|
tools/version_objects.py | Finds each US object in the other executables, function by function, and writes their splat subsegments with the US object names |
tools/version_share.py | Turns the objects that can share the US source into C, writes the symbol tables, and rewrites the #if blocks in src/ |
After a change that affects other releases (a newly matched function, a renamed symbol), rebuild
the US first: version_share.py reads the relocations of the US objects. Then run it with no
arguments, because the #if blocks are only rewritten when every release is analysed. Finally run
make VERSION=<serial> generate and make VERSION=<serial> check for each release.
An object stays in assembly in another release in these cases:
- It has
.dataof its own in C. Its data is not split yet in that release. - It is split in two places in the executable. This happens with some European objects.
- Its changed functions cannot be told apart. This happens with parts of the Japanese game code.
- It is a libpad unit and one of its functions differs. These units are assembled by GNU as,
which cannot take
INCLUDE_ASM.
🤖 Continuous Integration
.github/workflows/build.yaml builds every release on each push to
main. It runs make generate, make build and make report once per VERSION, then uploads each
build/<VERSION>/progress.json. The runner image and the disassembly tools are pinned for the
reason given in the Toolchain section.
🤝 How to Contribute
The most useful contribution is matching a function.
- Pick a function still under
INCLUDE_ASMinsrc/. - Write C for it, using
asm/scus_942.36/nonmatchings/<object>/<function>.sas reference. - Check it with
make check, objdiff, or a scratch on decomp.me.tools/decompile.pyextracts a function with its context and uploads it. - When it matches, replace the
INCLUDE_ASMline with the C and leave the original line commented above it, as everywhere else in the repository. - Rebuild the other releases (see How the versions share code). If
the function differs in a release,
version_share.pyadds the#iffor you.
Other help is just as welcome:
- 🔍 Naming: functions, data structures, execution flow
- 📝 Documentation: file formats and engine behaviour in
docs/ - 🐛 Bugs: open an issue with the log and the steps to reproduce
Pull requests: fork, create a branch, commit, and open the PR against main.
🗺️ Game Areas
Area and section layout of the game data, for orientation in area-specific code:
| ID | Area | Sections |
|---|---|---|
| AREA00 | Village of All Beginnings | 5 |
| AREA01 | Dwarf Forest | 5 |
| AREA02 | Dwarf Village | 6 |
| AREA03 | Phoenix Mountain | 6 |
| AREA04 | Haunted Mansion | 20 |
| AREA05 | Baccus Village | 4 |
| AREA06 | Motocross Segment | 3 |
| AREA07 | Dwarf Forest (Purified) | 5 |
| AREA08 | Baccus Lake | 4 |
| AREA09 | Mushroom Village | 7 |
| AREA10 | Deep Jungle | 9 |
| AREA11 | Village of Civilization | 3 |
| AREA12 | Haunted Mansion (Purified) | 20 |
| AREA13 | Pig Island | 2 |
| AREA14 | Evil Pigs | 8 |
| AREA15 | Empty / Unused | — |
| AREA16 | Village of Civilization — Clock Tower | 7 |
| AREA17 | Village of Civilization — Iron Tower | 11 |
| AREA18 | Village of Civilization — Y Crossing | 3 |
| AREA19 | Hidden Village | 3 |
📚 Documentation
In this repository:
Elsewhere:
- Tomba.Club, the community wiki
- PSX-SPX, hardware reference
- PSY-Q documentation
- Tomba! on TCRF
- decomp.me, collaborative function matching
⚖️ Legal
This project is for education and preservation only.
- No game assets or original code are distributed here.
- You need your own legally owned copy of the game to build anything.
- Tomba! is © Whoopee Camp / Sony Computer Entertainment.
🏆 Credits
- Hans Bonini: project lead and main development
Tools: splat (ethteck), spimdisasm (Decompollaborate), maspsx (mkst), objdiff (encounter), mkpsxiso (Lameguy64), and the PSX.Dev community.
Special thanks:
- zerovii: material and explanations about the WFM format
- vervalkon: material and explanations about quad polygon coordinates and the GAM format
- Xeeynamo: the Castlevania: SotN decompilation, used as reference
- LAB313Ru: PSX loader for Ghidra
- PCSX-Redux and DuckStation teams: emulators used for debugging and verification
📞 Community
- 💬 Discord: Tomba.Club
- 🌐 Website: hansbonini.com.br
<div align="center"> <strong>"Let's catch all the evil pigs!"</strong> — Tomba </div>
