Skip to content

About

No description, website, or topics provided.

Resources

Stars

12 stars

Watchers

2 watching

Forks

Repository files navigation

CPS3 C-BIOS

A progressive C reimplementation of parts of the CPS3 BIOS, cross-compiled with sh-elf-gcc for the SH-2 processor.

Everything here -- addresses, data structures, task/scheduler behavior, flash protocols -- was recovered through Ghidra-based reverse engineering of the original Capcom BIOS and the UltraBIOS; none of it comes from official documentation or source.

This is not a full BIOS rewrite: the large majority of the original Capcom BIOS binary is kept untouched. Specific points (task-table slots, function pointers, individual instructions) are patched with hooks that redirect execution into C code; that C code runs its own logic and then either returns to the original flow or dispatches into another original BIOS routine/task -- custom C and original BIOS code coexist and call into each other in the same running image.

Target: dead-cart CPS3 hardware (key1=0, key2=0) and MAME emulation.


Features

Main Menu

The C-BIOS replaces the BIOS MasterInitializer task with its own menu loop. The menu only appears when there is no game installed on the SIMM banks, or when START is held during boot; otherwise the system auto-boots straight into the installed game (see Boot Flow):

Item Action
1. RUN GAME (CD CHECK) Boot installed game with full CD verification
2. BOOT GAME Boot installed game directly (no CD, SIMM-only)
3. BOOT GAME REGION SELECT Boot with region selection screen
4. REWRITE NEW GAME Flash a new game from CD to SIMMs
5. SECURITY CASSETTE UTILITY Original BIOS cassette/flash menu
6. ABOUT Version info

Main Menu

CD-Optional Boot

Auto-boot, 2. BOOT GAME, and boot-with-region-select all dispatch into BIOS_TASK_BOOT_GAME, the same direct-boot task the original BIOS used internally -- it boots straight from the SIMM banks without going through the CD verification task (BIOS_TASK_CD_VERIFY, used only by 1. RUN GAME (CD CHECK)). No CD drive/disc needs to be present for these paths. Since this direct-boot behavior is reachable from the menu on any build, a separately patched "NOCD" firmware variant is not needed -- the same binary supports both CD-present and CD-absent operation.

Region Select

Controls

Every screen shows its available actions in the footer, following the original BIOS convention:

Hint Meaning
SELECT = 1P UP or DOWN Move the cursor
CHANGE = 1P LEFT or RIGHT Change the highlighted value
START = 1P SHOT1 Confirm / select
BACK = 1P SHOT2 Go back one screen

REWRITE NEW GAME

Selects a game from the embedded game list, then opens a per-game config screen before writing:

Rewrite New Game

Option Effect
REWRITE SIMM 1-6 Toggle whether each SIMM bank is written -- turn off the banks you don't need to touch so the rewrite only writes the selected ones instead of waiting through a full rewrite of all banks
SKIP ERASE [NOR] default (NOR-aware: skips erase for NOR replacement chips, normal original-BIOS erase for Capcom chips) / [YES] (skip for all chips) / [NO] (sector-erase NOR chips first)
SKIP VERIFY [NOR] default (NOR-aware: skips verify for NOR replacement chips, normal original-BIOS verify for Capcom chips) / [YES] (skip for all chips) / [NO] (verify via original BIOS)

Rewrite Config

Writes the selected game from CD to the SIMM banks. NOR replacement chips (Spansion S29GL128S, Micron MT28EW) are written via a custom AMD write-buffer implementation; original Capcom chips fall back to the original BIOS write routine.

This flow keeps the UltraBIOS memory-address patches, so any game in the embedded game table can be loaded dynamically at runtime instead of being hardcoded to a single title like the stock Capcom BIOS.

REWRITE NEW GAME reads standard UltraBIOS CDs directly, with two exceptions: SFIII: 3rd Strike MakotoFix and SFIII: 4th Strike are not distributed as standalone UltraBIOS CDs, so their ISO needs to be rebuilt first with the matching script from sfiii4s-custom.

NOR Chip Support

The existing Capcom chip types are not patched or modified -- their original identify/write/erase behavior is untouched. Support for NOR replacement chips is added on top, as new detection cases and dedicated write/erase routines, so both worlds coexist without changing how the original chips are handled. This is additive by design: identifying and handling further chip types (beyond Spansion/Micron) only requires adding new JEDEC ID cases and, if the protocol differs, a new write/erase routine -- no existing chip support needs to change.

Original Capcom chips and NOR replacements are detected and handled:

Type Chip Wiring
Fujitsu MBM29F400 Original AMD-compat
Intel / Sharp Original Intel protocol
Hitachi HM538123 Original WriteConst1
MXIC/Macronix Original Own protocol
Spansion S29GL128S (NOR) NOR replacement AMD-compat, NOR-wired
Micron MT28EW (NOR) NOR replacement AMD-compat, NOR-wired
Micron MT28EW (DS) NOR replacement AMD-compat, DS-wired

Typical NOR SIMM workflow

NOR replacement chips are wired so a physical HW dipswitch selects which slot is visible to the system -- multiple games can live on the same chip, one per slot. A practical way to load several games:

  1. From 5. SECURITY CASSETTE UTILITY -> FLASH MEMORY, erase the whole chip once.
  2. Go to 4. REWRITE NEW GAME and write the first game, leaving SKIP ERASE at its default ([NOR]) -- since the chip is already blank, this skips the sector-erase step and saves that time.
  3. When the write finishes, power off the system.
  4. Flip the HW dipswitch to the next slot.
  5. Power back on and repeat REWRITE NEW GAME for the next game -- still with SKIP ERASE at default, since that slot is blank too.

Prerequisites

Toolchain

sh-elf-gcc 13.2.0 + binutils 2.42, targeting SH-2 big-endian. The build runs inside a container -- you only need Podman (or Docker):

# macOS
brew install podman

# Verify
podman --version

The ./docker-make wrapper handles the rest, including the first-time toolchain image build (~25 minutes, one time only).

Python 3

Required for the patching scripts. Any Python 3.8+ works.

Base ROM

The build patches sfiii3_euro.29f400.u2 (Street Fighter III 3rd Strike, Euro). This proprietary Capcom binary is not included in the repository -- place your own dump in the project root before building.


Build

./docker-make                # compile + link + patch + deploy to MAME (USA region by default)
./docker-make REGION=3       # same, EURO region
./docker-make clean          # remove build artifacts
./docker-make info           # symbol-by-symbol disassembly

Region

The REGION parameter sets the region byte embedded in both output binaries:

Value Region
1 JAPAN
2 ASIA
3 EURO
4 USA
5 HISPANIC
6 BRAZIL
7 OCEANIA
8 ASIA NCD

The region is applied to the shared intermediate binary before the standard and custom variants are derived, so both outputs always carry the same region.

Output files:

File Description
build/cps3_cbios_standard.u2 Standard SH2 binary (unencrypted, for MAME cps3boot)
build/cps3_cbios_custom.u2 Custom SH2 binary (encrypted, for MAME cps3boota)

If MAME ROM directories are mounted (see docker-make), both files are deployed automatically.


Testing in MAME

mame cps3boot -bios 0 -debug

Load build/cps3_cbios_standard.u2 as the flash ROM (no-battery_bios_29f400_for_hd6417095_sh2.u2).

For the dead-cart / encrypted variant (cps3boota), use build/cps3_cbios_custom.u2.

Note: mame resolves roms/, cfg/, nvram/, etc. relative to its own working directory, so run it from wherever your MAME install expects those folders rather than from the project directory.


Boot Flow (summary)

reset -> BIOS phases 1-8 (original Capcom code)
      -> phase 9 stub  @ 0x20000  -> bridge to 0x498
      -> phase 10 stub @ 0x2028   -> C runtime init (BSS zero + data copy)
      -> phase 11 stub @ 0x1B00   -> PR = cps3_kernel_main, RTS
      -> cps3_kernel_main         -> jumps to BIOS scheduler entry @ 0xEC8
      -> task[0] = cps3_master_init  (replaces MasterInitializer)

Only phases 9-11 run as C; phases 1-8 still run as unmodified original Capcom BIOS code. src/crt0.s (a phase 1 replacement) exists in the tree but is not part of the active build (see ASM_SRC in the Makefile).

The scheduler is intercepted at task[0]. Tasks [1..14] (CD verify, flash write, region menu, etc.) are dispatched by returning the appropriate state from that hook -- the BIOS scheduler calls them normally.

cps3_master_init -- what runs on every boot

The menu is not shown unconditionally. cps3_master_init runs the original HW init first, then decides between auto-boot and the menu:

cps3_master_init:
  1. BIOS_MASTER_INIT()                 -- original HW init (font, tilemap, ISRs)
  2. Pre-load REGION_SELECTED_BYTE from flash (fallback for every boot path)
  3. Re-entry check (SKIP_MENU_FLAG set by a prior menu action, e.g. after
     REWRITE's CRT0 restart) -> return immediately, let the BIOS scheduler
     continue into the requested task (no menu, no input read)
  4. Read input once. If START is NOT held AND a game is already written
     to the SIMM banks (header check against flash) -> auto-boot directly
     into BIOS_TASK_BOOT_GAME, skipping the menu entirely
  5. Otherwise (no game installed, OR START held at power-on to force
     maintenance mode) -> enter the C-BIOS main menu loop

So in practice: a cabinet with a game already flashed boots straight into that game with no menu, unless START is held during power-on. The menu only appears by default when the SIMMs are blank/unrecognized (nothing to boot).

About

No description, website, or topics provided.

Resources

Stars

12 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages