Skip to content
PORTSNATIVE.
HomeCatalog
Web GamesEmulatorsToolsNews
PORTSNATIVE.

A catalog for discovering ports and related projects. We link to official sources and do not host original game files.

ExploreCatalogMy list
InformationAbout usSuggest a portSupportDonationsLegal notice
© 2026 PortsNative
Back to catalog
Need for Speed: High Stakes (PS1)
PORTSNATIVE

Need for Speed: High Stakes (PS1)

NATIVE PORTRACING / DRIVINGWINDOWSLINUXMACOSALPHA

Need for Speed: High Stakes (PS1)

OriginPlayStation

TechnologyNative C/C++ port (engine reimplementation)

Available forWindows, Linux, macOS

View official project

About the project

Need for Speed (NFS) es una franquicia de videojuegos de carreras y aventuras publicada por Electronic Arts. La serie se centra, principalmente, en las carreras callejeras ilícitas y, en general, les da el papel a los jugadores de completar varios tipos de carreras, infringiendo en más de una ocasión la ley local mientras evaden persecuciones policiales. La serie lanzó su primer título, The Need for Speed en 1994. El título proviene de una famosa cita de la película de 1986 Top Gun.

Official project information

Author's original READMEOpen on GitHub ↗

nfs4-decomp — Need for Speed: High Stakes (PSX) matching decompilation

⚠️ NO LICENSE GRANTED — ALL RIGHTS RESERVED

This repository carries no open-source license. Viewing and forking on GitHub are the only permitted acts (GitHub ToS §D.5). Any other use — ports, builds, redistribution, re-hosting, or derivative works of any kind — is prohibited without the author's prior written authorization and constitutes copyright infringement. See LICENSE. Authorization requests: via the author's GitHub profile. Need for Speed IV and its game code/assets remain the property of Electronic Arts Inc.; no game assets or proprietary compiler binaries are distributed here.

📢 Official port project

The authorized port of this decompilation lives at XProger/NFSHS-PSX-decomp-port — NFS4 decomp project ports, by XProger. It is the only port carrying the author's written authorization under the LICENSE; any other port remains unauthorized.

A byte-matching decompilation of the PSX build of Need for Speed: High Stakes (nfs4-f, EA 1999), in the Silent Hill decomp mould: splat-split asm, INCLUDE_ASM-based mixed translation units, and objdiff per-function matching against the original binary.

Goal: recompile each function to a byte-identical object (per-function 100% matching, objdiff/decomp.dev). This is the matching track — distinct from the sibling "compile + link + run" reconstruction (reconstructed_headers/tree).

👉 Read METHODOLOGY.md FIRST

METHODOLOGY.md is the matching playbook — the two hard rules (100%-only; the disasm-v4.txt oracle), the per-function workflow, the technique catalog (symptom → fix), permuter usage, the data-mat pass, and the live status. If you're an agent resuming after /compact, open it before touching anything.

Status

The full pipeline is wired and proven end-to-end (splat → real PsyQ cc1 2.8.0 → maspsx/aspsx 2.77 → GNU as → ELF → objdiff), CI-green on a Windows runner, and live on decomp.dev.

Per-function matching is the active work. First module under attack is game/common/aiinit (objdiff unit): 12/17 functions byte-perfect (50%); overall 0.48%. See METHODOLOGY.md for the live table and the remaining (gcc register-allocation–bound) near-misses.

Toolchain

The original was built with SN/PsyQ 4.3: cc1 GNU C 2.8.0 + ASPSX 2.77. We drive the real cc1 and replace ASPSX with maspsx

  • GNU as (produces ELF for objdiff). Configured in tools/build.py:
  • CC1PSX.EXE — C:/Temp/psq43/COMPILER/ (real PsyQ compiler)
  • maspsx.py — C:/Temp/maspsx-master/ (--aspsx-version=2.77)
  • mipsel-none-elf-{as,ld,objcopy} — C:/Tools/mips-ps1/mips/bin/ (binutils 2.43)
  • splat — C:/Temp/splat-main/ (run under Python 3.12, which has rabbitizer/spimdisasm)

Build flags: cc1 -O2 -G4, maspsx --aspsx-version=2.77 -G4 (forces as -G0).

Layout

configs/nfs4.yaml          splat config (PS-EXE @0x80010000, t_size 0x12E000)
configs/symbol_addrs.txt    VA->name, generated from NFS4.MAP (tools/gen_symbols.py)
include/decomp/types.h      s8/u32/q19_12 ... fixed-width + Q-format aliases
include/decomp/include_asm.h INCLUDE_ASM macro (maspsx-keep variant)
include/macro.inc           glabel/jlabel/dlabel/alabel/endlabel (jlabel is global)
include/common.h            master include for every src/*.c
src/main.c                  the main .text TU (C stubs + INCLUDE_ASM per fn)
asm/nonmatchings/main/*.s    per-function disassembly
asm/data/*.s, asm/header.s   data sections + PS-EXE header
linkers/nfs4.ld             splat-generated linker script
rom/nfs4-f.exe              the target (NOT committed — sha1 b48ea3452e64...)
rom/NFS4.MAP                retail link map from the disc (NOT committed — md5
                            12326ebd37ed...)
rom/NFS4.SYM                retail symbol file from the disc (NOT committed); tools/retail_sym.py
                            dumps it with tools/dumpsym/ into build/sym/ on first use
tools/build.py              cpp->cc1->maspsx->as->ld->objcopy + byte-diff report
tools/gen_symbols.py        NFS4.MAP -> symbol_addrs.txt (sanitizes . and case clashes)
tools/fix_gte.py            rewrite GTE compute ops (rtps/mvmva/...) to .word
tools/audit_vtable_indexing.py  reject _vf indexing that scales by a whole vtable row

Build

To produce the two disc files NFS4.EXE and FRONT.BIN (byte-identical to retail) see BUILDING.md.

# 1. (re)generate symbols + split  — only when configs change
py -3.12 tools/gen_symbols.py
py -3.12 C:/Temp/splat-main/split.py configs/nfs4.yaml
py -3.12 tools/fix_gte.py            # GTE compute ops GNU as can't assemble
py -3.12 tools/audit_vtable_indexing.py  # static vtable OOB regression audit

# 2. build + verify against rom/nfs4-f.exe
py -3.12 tools/build.py              # full asm build + link + diff report
py -3.12 tools/build.py --skip-asm   # C-only (objdiff / decomp.me style)
py -3.12 tools/build.py clean

Key solved gotchas

  • cfront names (_._14X dtors, _vt.16Y) aren't valid C identifiers → gen_symbols.py folds illegal chars to _ (byte-match only cares about addresses, not label spelling) and disambiguates case-insensitive clashes (CD_init vs CD_Init collide as filenames on Windows).
  • GTE compute ops (rtps, rtpt, mvmva, nclip, gpf, ...) are unknown to GNU as; fix_gte.py rewrites them to .word using the exact bytes splat prints in each line's comment — zero encoding risk.
  • Jump tables live in the rodata object but target function-internal labels; jlabel is defined global in macro.inc so the cross-object .word .L* references resolve (labels are link-time → no byte change).

Progress tracking (objdiff / decomp.dev)

objdiff.json diffs each unit's target (expected/ = asm build = original bytes) against the base (build/ = --skip-asm, only decompiled C). Generate the report locally:

py -3.12 tools/build.py --out expected --no-link   # target objects (once)
py -3.12 tools/build.py --skip-asm                  # base objects
tools/objdiff/objdiff-cli.exe report generate -p . -o build/report.binpb -f proto

This is a per-object diff, so it does not depend on the whole-image link. Current overall: ~0.48 % and climbing as functions are matched one at a time (see METHODOLOGY.md for the per-function workflow and status).

decomp.dev ingests that report via CI: .github/workflows/report.yml (windows runner, native cc1) builds it and uploads the artifact nfs4-f_report. Then add the project on decomp.dev and install its GitHub App. The workflow needs a one-time TOOLCHAIN_ZIP_URL secret = the toolchain download link (PsyQ cc1 is copyrighted, so it's not committed). A Dropbox share link works directly (the workflow forces dl=1) — see the workflow header.

Next steps (toward 100% match)

The active strategy is per-function matching, one function at a time, against the objdiff expected/ (asm) target — see METHODOLOGY.md for the workflow, technique catalog, and live status. In short:

  1. Finish the aiinit unit (5 near-misses left, all gcc register-allocation / induction-variable bound — the hard tail).
  2. Vendor the next reconstruction module as a new objdiff unit and repeat.
  3. Whole-image link/layout is a separate, later concern; matching is per-object and does not depend on it.
View official project
CALIFICACIÓN
—
Loading votes…
Advertisement

PROJECT FILE

Project type
NATIVE PORT
Genre
Racing / Driving
Status
alpha
Original platform
PlayStation
Technology
Native C/C++ port (engine reimplementation)
Version
—
Updated
—

Target platforms 3

Windows
Linux
macOS
View on GitHub
Advertisement