oot Documentation

Decompilation of The Legend of Zelda: Ocarina of Time

5,456 stars C C 1 file ยท ~10,905 tokens
RAW Doc

1. Project Overview & Quickstart (zeldaret/oot)

File: README.md

The Legend of Zelda: Ocarina of Time

Build Status Decompilation Progress Contributors Discord Channel

diff
- WARNING! -

This repository is a work in progress, and while it can be used to make certain changes, it's still
constantly evolving. If you use it for modding purposes in its current state, please be aware that
the codebase can drastically change at any time. Also note that some parts of the ROM may not be
'shiftable' yet, so modifying them could be difficult at this point.

This is a WIP decompilation of The Legend of Zelda: Ocarina of Time. The purpose of the project is to recreate a source code base for the game from scratch, using information found inside the game along with static and/or dynamic analysis. It is not producing a PC port. For more information you can get in touch with the team on our Discord server.

It builds the following versions:

Name Build timestamp Description MD5 hash of input ROM(s)
ntsc-1.0 98-10-21 04:56:31 NTSC 1.0 (Japan/US) 9f04c8e68534b870f707c247fa4b50fc``5bd1fe107bf8106b2ab6650abecd54d6
ntsc-1.1 98-10-26 10:58:45 NTSC 1.1 (Japan/US) 1bf5f42b98c3e97948f01155f12e2d88``721fdcc6f5f34be55c43a807f2a16af4
pal-1.0 98-11-10 14:34:22 PAL 1.0 (Europe) e040de91a74b61e3201db0e2323f768a
ntsc-1.2 98-11-12 18:17:03 NTSC 1.2 (Japan/US) 2258052847bdd056c8406a9ef6427f13``57a9719ad547c516342e1a15d5c28c3d
pal-1.1 98-11-18 17:36:49 PAL 1.1 (Europe) d714580dd74c2c033f5e1b6dc0aeac77
gc-jp 02-10-29 23:49:53 GameCube Japan 33fb7852c180b18ea0b9620b630f413f
gc-jp-mq 02-10-30 00:15:15 GameCube Japan Master Quest 69895c5c78442260f6eafb2506dc482a
gc-us 02-12-19 13:28:09 GameCube US cd09029edcfb7c097ac01986a0f83d3f
gc-us-mq 02-12-19 14:05:42 GameCube US Master Quest da35577fe54579f6a266931cc75f512d
gc-eu-dbg-2 03-02-13 19:46:49 GameCube Europe/PAL Debug (earlier build) ab1ca59d0039e3b34d82db650b54d7b9``2814fde8d6cfe23a220de6be955b4196
gc-eu-mq-dbg 03-02-21 00:16:31 GameCube Europe/PAL Master Quest Debug 75e344f41c26ec2ec5ad92caa9e25629``8ca71e87de4ce5e9f6ec916202a623e9``f751d1a097764e2337b1ac9ba1e27699``dde376d47187b931820d5b2957cded14
gc-eu-dbg 03-02-21 00:49:18 GameCube Europe/PAL Debug 3c10b67a76616ae2c162def7528724cf``382dc484e317d6522745c95387e7d5b9
gc-eu 03-02-21 20:12:23 GameCube Europe/PAL 2c27b4e000e85fd78dbca551f1b1c965
gc-eu-mq 03-02-21 20:37:19 GameCube Europe/PAL Master Quest 1618403427e4344a57833043db5ce3c3
gc-jp-ce 03-10-08 21:53:00 GameCube Japan (Collector's Edition Disc) 0c13e0449a28ea5b925cdb8af8d29768
ique-cn 03-10-22 16:23:19 iQue Player (Simplified Chinese) 0ab48b2d44a74b3bb2d384f6170c2742

The default version is gc-eu-mq-dbg, i.e. the GameCube Europe/PAL Master Quest Debug ROM.

Note: This repository does not include any of the assets necessary to build the ROM. A prior copy of the game is required to extract the needed assets.

Website: https://zelda.deco.mp

Discord: https://discord.zelda.deco.mp

Installation

We recommend using WSL on Windows, or native Linux, which the rest of this readme describes. We currently have instructions for

(These will also depend on the Linux instructions.)
Some of these may also be out of date or unmaintained; usually our contributors use WSL, Linux, and macOS, so these instructions should be up to date.

Windows

For Windows 10 or 11, install WSL and a distribution by following this
WSL Installation Guide.
We recommend using Ubuntu as the Linux distribution.

For older versions of Windows, install a Linux VM or refer to Docker instructions.

Linux (Native or under WSL / VM)

1. Install build dependencies

The build process has the following package requirements:

  • git
  • build-essential
  • curl
  • python3
  • python3-pip
  • python3-venv
  • libxml2-dev

Python 3.10+ is required.

Under Debian / Ubuntu (which we recommend using), you can install them with the following commands:

bash
sudo apt-get update
sudo apt-get install git build-essential curl python3 python3-pip python3-venv libxml2-dev

In addition to these packages, a MIPS binutils installation is required. The project aims to support a couple of commonly-encountered MIPS toolchains out-of-the-box, only one is required and is automatically detected:

If none of these are available to install, the makefile exposes MIPS_BINUTILS_PREFIX as a means to set your own toolchain prefix. Otherwise, consider building one of the first two options from source.

If you are using GCC as the compiler for Ocarina of Time, you will also need the corresponding gcc compiler for the chosen toolchain. For the first two options above, gcc is included automatically. For mips-linux-gnu- or mips64-linux-gnu- it is often a separate package, e.g. gcc-mips-linux-gnu.

2. Clone the repository

N.B. If using WSL, we strongly encourage you to clone into WSL's Linux filesystem using Linux's git.
Cloning into the Windows filesystem will result in much slower read/write speeds, and often causes issues when Windows copies the files with the wrong line endings, which the compiler IDO cannot handle correctly.

Clone https://github.com/zeldaret/oot.git where you wish to have the project, with a command such as:

bash
git clone https://github.com/zeldaret/oot.git

This will copy the GitHub repository contents into a new folder in the current directory called oot. Change into this directory before doing anything else:

bash
cd oot

3. Prepare a base ROM

First, pick the version of the game you want to build.
The supported versions and ROM checksums can be found in the table above.
As an example, the ntsc-1.0 version will be used in these instructions.

Place a copy of the ROM inside the baseroms// folder for your version of choice.
For example for ntsc-1.0, inside the baseroms/ntsc-1.0/ folder.
If you are under WSL, you can run the command explorer.exe . to open the current directory in the Windows file explorer.

Rename the file to baserom.z64, baserom.n64 or baserom.v64, depending on the original extension.

4. Setup the ROM and build process

Setup and extract everything from your ROM with the following command:

bash
make setup VERSION=

For example for ntsc-1.0, run make setup VERSION=ntsc-1.0.

This downloads some dependencies (from pip), and compiles tools for the build process.
Then it generates a new ROM baseroms//baserom-decompressed.z64.
For retail (non-debug) versions, that ROM will be the decompressed equivalent of the ROM.
For the gc-eu-mq-dbg version, that ROM will have the overdump removed and the header patched.
The other debug ROMs gc-eu-dbg-2 and gc-eu-dbg will also have the overdump removed.
It will also extract the individual assets from the ROM.

5. Build the ROM

Run make to build the ROM.
Make sure your path to the project is not too long, otherwise this process may error.

bash
make VERSION=

For example for ntsc-1.0, run make VERSION=ntsc-1.0

If all goes well, a new ROM should be built at build//oot-.z64 (for example build/ntsc-1.0/oot-ntsc-1.0.z64), and the following text printed:

text
build//oot-.z64: OK

If you instead see the following:

text
build//oot-.z64: FAILED
md5sum: WARNING: 1 computed checksum did NOT match

This means that the built ROM isn't the same as the base one, so something went wrong or some part of the code doesn't match.

NOTE: to speed up the build, you can either:

  • pass -jN to make setup and make, where N is the number of threads to use in the build. The generally-accepted wisdom is to use the number of virtual cores your computer has.
  • pass -j to make setup and make, to use as many threads as possible, but beware that this can use too much memory on lower-end systems.

Both of these have the disadvantage that the ordering of the terminal output is scrambled, so for debugging it is best to stick to one thread (i.e. not pass -j or -jN).

Changing build options

By default, if you don't specify a version to build with VERSION= in the make commands, the gc-eu-mq-dbg version is used.
This default can be changed in the Makefile.

The project Makefile is fairly configurable and can also be used to prepare the repo for modding.
See the options outlined at the top of the Makefile for more information.

Contributing

All contributions are welcome. This is a group effort, and even small contributions can make a difference.
Some tasks also don't require much knowledge to get started.

Most discussions happen on our Discord Server, where you are welcome to ask if you need help getting started, or if you have any questions regarding this project and other decompilation projects.


File: docs/audio/Samplebank_XML.md

Samplebank XML Format Specification

Samplebank XMLs describe a samplebank file that contains compressed waveform data. It specifies which sample files to include as well as certain global properties such as the index of this samplebank.


xml
<SampleBank
    Name="<C Indentifier>"
    Index=""
    Medium="<Medium>"
    CachePolicy="<CachePolicy>"
    BufferBug="[bool]"
>

Begins a new samplebank.

Attributes

  • Name: The name of the samplebank.
  • Index: The index of the samplebank for the samplebank table. Must be a unique index for all samplebanks and pointers.
  • Medium: The storage medium, from the SampleMedium enum.
  • CachePolicy: The cache policy, from the AudioCacheLoadType enum.
  • [Optional] BufferBug: Whether this samplebank suffers from a buffer clearing bug present in the original audio tools. For matching only.

Tags

  • xml
    "
    />

    Create an alternate index that refers to this samplebank.

    Attributes

    • Index: The alternative index, must be unique among all samplebanks and pointers.

  • xml
    <Sample
        Name="<C Identifier>"
        Path=""
    />

    Adds a compressed sample file to the samplebank. The sample should be single-channel and big-endian, in a format that is recognizable by the audio driver such as: pcm16, vadpcm, or half-frame vadpcm.

    Attributes

    • Name: Name of this sample. Must be a valid C language identifier.
    • Path: Path to aifc file relative to the project root (typically in $(BUILD_DIR)/assets/audio/samples/)

  • xml
    "
        Path=""
    />

    Adds a binary blob to the samplebank. Intended for matching only when data cannot be identified.

    Attributes

    • Name: Name of this blob. Must be a valid C language identifier.
    • Path: Path to binary file, relative to the project root (typically in $(BUILD_DIR)/assets/audio/samples/)

xml
</SampleBank>


File: docs/audio/Soundfont_XML.md

Soundfont XML Format Specification

Soundfont XMLs describe the layout of a single soundfont. These package raw samples together into instruments, of which there are three kinds:

  • Effects: These are simple sound effects that just play a single sample without any modulation.
  • Drums: These define a MIDI-style percussion key map.
  • Instruments: These are instruments that may be played at any key with up to three voices and may be modulated by an envelope.

In the specification, Note Names can be either a MIDI note name e.g. C4 or it may be a Zelda64 note number, which are related to MIDI note numbers ($n$) by $(n - 21) \mod 128$.


xml
<Soundfont
    Name="<C Identifier>"
    Index=""
    Medium="<Medium>"
    CachePolicy="<CachePolicy>"
    SampleBank=""
    Indirect="[uint]"
    SampleBankDD="[Path]"
    IndirectDD="[uint]"
    LoopsHaveFrames="[bool]"
    PadToSize="[uint]"
    NumInstruments="[uint]"
>

Begins a new soundfont.

Attributes

  • Name: Soundfont symbol name. Must be a valid C identifier.
  • Index: Soundfont index. Must be an integer.
  • Medium: Storage medium. Must be an enum name from SampleMedium.
  • CachePolicy: Cache policy. Must be an enum name from AudioCacheLoadType.
  • SampleBank: Path to samplebank xml used by this soundfont.
  • [Optional] Indirect: Pointer index if the samplebank is referenced indirectly.
  • [Optional] SampleBankDD: Path to samplebank xml used for DD medium.
  • [Optional] IndirectDD: Pointer index if the DD samplebank is referenced indirectly.
  • [Optional] LoopsHaveFrames: Whether loops in this soundfont store the total frame count of the sample. Must be a boolean.
  • [Optional] PadToSize: For matching only. Specifies the total file size the result output should be padded to.
  • [Optional] NumInstruments: For matching only. Specifies the total number of instrument pointers. Usually this is automatically assigned based on max(program_number) + 1 but some vanilla banks don't match this way.

Tags

  • xml
    <Envelopes>

    Lists envelopes defined in this soundfont.

    Attributes

    N/A

    Tags

    • xml
      <Envelope
          Name="<C Identifier>"
          Release=""
      >

      Starts a new envelope.

      Attributes

      • Name: Unique name for this envelope. Must be a valid C identifier.
      • Release: Release rate index (into gAudioCtx.adsrDecayTable) for this envelope

      Tags

      • xml
        "
            Arg="<s16>"
        />

        Add a point to the envelope at (delay, arg)

        Attributes

        • Delay: Duration until the next point
        • Arg: Value of the envelope at this point

      • xml
        <Disable/>

        Insert a ADSR_DISABLE command


      • xml
        <Hang/>

        Insert a ADSR_HANG command


      • xml
        <Goto
            Index=""
        />

        Insert a ADSR_GOTO command

        Attributes

        • Index: Index of the envelope point to jump to

      xml
      </Envelope>

    xml
    </Envelopes>

  • xml
    <Samples
        IsDD="[Bool]"
        Cached="[Bool]"
    >

    Begins a list of samples used in this Soundfont.

    Attributes

    • [Optional] IsDD: Whether all the samples in the list are on the Disk Drive. The sample data will come from the samplebank SampleBankDD. Default is false. NOTE this is not fully implemented, it should always be false.
    • [Optional] Cached: Whether all the samples in the list should be added to the usedSamples cache. Default is false.

    Tags

    • xml
      <Sample
          Name="<C Identifier>"
          SampleRate="[Sample Rate]"
          BaseNote="[Note Name]"
          FineTune="[Fine Tune]"
          IsDD="[Bool]"
          Cached="[Bool]"
      />

      Declares a sample used in this soundfont.

      Attributes

      • Name: The name of this sample. A sample with this name must be present in the samplebank used by the soundfont.
      • [Optional] SampleRate: An overriding sample rate for this sample. Default comes from the sample file.
      • [Optional] BaseNote: An overriding root key for this sample. Default comes from the sample file.
      • [Optional] FineTune: An overriding fine tuning for this sample, in cents, in the range [-100, 100]. Default comes from the sample file.
      • [Optional] IsDD: Whether this sample is on the Disk Drive. The sample data will come from the samplebank SampleBankDD. Default is false. NOTE this is not fully implemented, it should always be false.
      • [Optional] Cached: Whether this sample should be added to the usedSamples cache. Default is false.

    xml
    </Samples>

  • xml
    <Effects>

    Begins a list of sound effects to define for this soundfont. Sound effects correspond to simple sounds that cannot be played at different keys.

    Attributes

    N/A

    Tags

    • xml
      <Effect
          Name="<C Identifier>"
          Sample="<Sample Name>"
          SampleRate="[Sample Rate]"
          BaseNote="[Note Name]"
          FineTune="[Fine Tune]"
      />

      Defines a single sound effect.

      Attributes

      • Name: The name of the sound effect, the name is made available in sequence files in the form SF{n}_{name} where n is the index of this soundfont and name is this name. For example, if n=0 and name=ExampleEffect the name to use in sequence files is SF0_ExampleEffect.
      • Sample: The name of the sample associated with this effect.
      • [Optional] SampleRate: An overriding sample rate for this effect. Default comes from the sample definition.
      • [Optional] BaseNote: An overriding root key for this effect. Default comes from the sample definition.
      • [Optional] FineTune: An overriding fine tuning for this effect, in cents, in the range [-100, 100]. Default comes from the sample definition.

    xml
    </Effects>

  • xml
    <Drums>

    Begins the percussion definitions for this soundfont. Percussion corresponds to the MIDI notion of percussion, where single samples are mapped across a range of keys.

    Attributes

    N/A

    Tags

    • xml
      <Drum
          Name="<C Identifier>"
          Note="[Note Name]"
          NoteStart="[Note Name]"
          NoteEnd="[Note Name]"
          Pan=""
          Envelope="<Envelope Name>"
          Release="[u8]"
          Sample="<Sample Name>"
          SampleRate="[Sample Rate]"
          BaseNote="[Note Name]"
          FineTune="[Fine Tune]"
      />

      Defines a single percussion range.

      Attributes

      • Name: The name of this sound. Definitions are emitted for sequence files in the form SF{n}_{name}_{note} for every note covered by this sound.
      • [Optional] Note: The key to map this sound to. Should not overlap with other definitions. If this field is left unspecified, NoteStart and NoteEnd become required.
      • [Optional] NoteStart: The first key that is mapped to this sound. Should not overlap with other definitions. If this field is left unspecified, Note becomes required. If this field is specified, NoteEnd must also be specified.
      • [Optional] NoteEnd: The last key that is mapped to this sound. Should not overlap with other definitions. If this field is left unspecified, Note becomes required. If this field is specified, NoteStart must also be specified.
      • Pan: The stereo weight for this sound. Center=64.
      • Envelope: The envelope to modulate the volume over time with. Must be defined in the Envelopes list.
      • [Optional] Release: An override for the envelope release rate. Default is the release rate specified in the envelope definition
      • Sample: The name of the sample to use.
      • [Optional] SampleRate: An overriding sample rate for this sound. Default comes from the sample definition.
      • [Optional] BaseNote: An overriding root key for this sound. Default comes from the sample definition.
      • [Optional] FineTune: An overriding fine tuning for this sound, in cents, in the range [-100, 100]. Default comes from the sample definition.

    xml
    </Drums>

  • xml

    Begins the instrument definitions for this soundfont. Instruments correspond to the MIDI notion of instruments, with up to 3 samples (voices) per instrument that must map to contiguous ranges of notes.

    Attributes

    N/A

    Tags

    • xml
      "
          Name="<C Identifier>"
          Envelope="<Envelope Name>"
          Release="[u8]"
      
          Sample="<Sample Name>"
          SampleRate="[Sample Rate]"
          BaseNote="[Note Name]"
          FineTune="[Fine Tune]"
      
          RangeLo="[Note Name]"
          SampleLo="[Sample Name]"
          SampleRateLo="[Sample Rate]"
          BaseNoteLo="[Note Name]"
          FineTuneLo="[Fine Tune]"
      
          RangeHi="[Note Name]"
          SampleHi="[Sample Name]"
          SampleRateHi="[Sample Rate]"
          BaseNoteHi="[Note Name]"
          FineTuneHi="[Fine Tune]"
      />

      Defines an instrument.

      Attributes

      • ProgramNumber: MIDI Program Number for this instrument. Must be in the range 0 <= n <= 125
      • Name: The name of this instrument.
      • Envelope: Envelope to use, identified by name.
      • [Optional] Release: Release rate index override. Default release rate comes from the chosen envelope.
      • Sample: The name of the middle sample to use for this instrument.
      • [Optional] SampleRate: Sample rate override for the middle sample. Default is sourced from the sample properties.
      • [Optional] BaseNote: Base note override for the middle sample. Default is sourced from the sample properties.
      • [Optional] FineTune: Fine tuning override for the middle sample, in cents, in the range [-100, 100]. Default is sourced from the sample properties.
      • [Optional] RangeLo: The largest note for SampleLo. SampleLo will be used instead of Sample for keys in the range [0, RangeLo]. If left unspecified, SampleLo must not be specified. If specified, SampleLo must be specified.
      • [Optional] SampleLo: The name of the low sample to use for this instrument.
      • [Optional] SampleRateLo: Sample rate override for the low sample. Default is sourced from the sample properties.
      • [Optional] BaseNoteLo: Base note override for the low sample. Default is sourced from the sample properties.
      • [Optional] FineTuneLo: Fine tuning override for the low sample, in cents, in the range [-100, 100]. Default is sourced from the sample properties.
      • [Optional] RangeHi: The smallest note for SampleHi. SampleHi will be used instead of Sample for keys in the range [RangeHi, 127]. If left unspecified, SampleHi must not be specified. If specified, SampleHi must be specified.
      • [Optional] SampleHi: The name of the high sample to use for this instrument.
      • [Optional] SampleRateHi: Sample rate override for the high sample. Default is sourced from the sample properties.
      • [Optional] BaseNoteHi: Base note override for the high sample. Default is sourced from the sample properties.
      • [Optional] FineTuneHi: Fine tuning override for the high sample, in cents, in the range [-100, 100]. Default is sourced from the sample properties.

    xml

xml
</Soundfont>


File: docs/BUILDING_DOCKER.md

Building using Docker

1. Setup requirements

To use Docker, you'll need either Docker Desktop or Docker Toolbox installed and setup based on your system.

On Ubuntu, Docker and required tools can be installed with: sudo apt install docker.io docker-compose docker-buildx

You'll also need to prepare a local version of the project with a copied base ROM (see steps 2 and 3 of the Linux instructions).

2. Create and start the Docker image build

From the root of your local project, run the following command:

bash
docker-compose up --build

This should immediately begin steps 4 and 5 within the Docker container.

3. Shell into the 'oot' container

To exec into the oot Docker image at any time, run the following command either during or after the build:

bash
docker-compose exec oot bash

File: docs/BUILDING_MACOS.md

Building on macOS

N.B. C++17 is required to build the asset processing program that we use (ZAPD), so check your OS version can support this before proceeding.

1. Dependencies

For macOS, use Homebrew to install the following dependencies:

  • coreutils
  • make
  • python3
  • bash
  • clang-format
  • libxml2
  • libiconv

You can install them with the following commands:

bash
brew update
brew install coreutils make python3 bash clang-format libxml2 libiconv

(The repository expects Homebrew-installed programs to be either linked correctly in $PATH etc. or in their default locations.)

2. Building mips-linux-binutils

The following instructions are written for MacOS users but should apply to any Unix-like system, with maybe some modifications at the end regarding the bash_profile.

Create destination dir for binutils

bash
sudo mkdir -p /opt/cross

Create and enter local working dir

bash
mkdir ~/binutils-tmp
cd ~/binutils-tmp

Get and extract binutils source

bash
curl -O https://ftp.gnu.org/gnu/binutils/binutils-2.46.0.tar.xz
tar xjf binutils-2.46.0.tar.xz

Create and enter a build directory

bash
mkdir build-binutils
cd build-binutils

Configure the build

bash
../binutils-2.46.0/configure --target=mips-linux-gnu --prefix=/opt/cross --with-system-zlib --disable-gprof --disable-gdb --disable-werror

Make and install binutils

bash
make -j$(nproc)
sudo make install

Edit your ~/.bash_profile/~/.zprofile (or whichever shell you use) to add the new binutils binaries to the system PATH

bash
echo 'export PATH="$PATH:/opt/cross/bin"' >> ~/.bash_profile

Reload ~/.bash_profile (or just launch a new terminal tab)

bash
source ~/.bash_profile

If this worked, you can now delete the temporary directory ~/binutils-tmp.

3. Final note

Apple's version of make is very out-of-date, so you should use the brew-installed gmake in place of make in this repo from now on.

You should now be able to continue from step 2 of the Linux instructions.

4. Building GCC (optional)

If you'd like to compile with GCC instead of IDO (e.g. for modding), you can build it from source similarly to how we built binutils:

Install dependences

bash
brew install gcc@15 gmp isl libmpc mpfr

Create and enter local working dir

bash
mkdir ~/gcc-tmp
cd ~/gcc-tmp

Get and extract gcc source

bash
curl -O https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz
tar xvf gcc-15.2.0.tar.xz

Create and enter a build directory

bash
mkdir build-gcc
cd build-gcc

Configure the build

bash
CC=gcc-15 CXX=g++-15 ../gcc-15.2.0/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-nls --enable-languages=c --with-gmp=$(brew --prefix)/opt/gmp --with-mpfr=$(brew --prefix)/opt/mpfr --with-mpc=$(brew --prefix)/opt/libmpc --with-isl=$(brew --prefix)/opt/isl

Make and install gcc

bash
CC=gcc-15 CXX=g++-15 make all-gcc -j$(nproc)
sudo make install-gcc

If this worked, you can now delete the temporary directory ~/gcc-tmp.


File: docs/compilers.md

Compilers

Ocarina of Time was written mostly in C, compiled to MIPS machine code. For the
N64 and GameCube versions, all code was compiled with the IDO compiler. For the
iQue Player versions, some of the code (namely libultra, and some game files
such as those related to Chinese text) was compiled with the EGCS compiler instead.

IDO

Ocarina of Time was originally developed on
Silicon Graphics "Indy" workstations,
and IDO (IRIS Development Option) was the C compiler toolchain that shipped with
these. Two different versions of IDO were used for Ocarina of Time: IDO 5.3 was
used for some libraries (namely libultra, libleo, and the JPEG library) while
IDO 7.1 was used for the other libraries and all of the "main" game code.

These Silicon Graphics workstations ran the MIPS-based IRIX operating system, so
the original compiler binaries can't run on modern systems. Originally this
project used qemu-irix (now
unmaintained) to run emulate IRIX on modern systems, but nowadays we use the
more lightweight
ido-static-recomp instead.

EGCS

EGCS (Experimental/Enhanced GNU Compiler System)
was a fork of the GCC compiler. The Linux-based iQue SDK included a patched
version of EGCS release 1.1.2. The original compiler can still run on modern Linux
systems, but we use a
modified version
that includes Mac support and a few other minor improvements (such as anonymous
struct/union support).

This version of the EGCS compiler has a bug where code that indexes into an array member can
fail to compile if the array member is at a large (>= 0x8000) offset in a struct. For
example, when run on the source code

c
struct Foo {
    char a[0x8000];
    int b[1];
};

int test(struct Foo* foo, int i) {
    return foo->b[i];
}

the compiler errors with

text
Compiler error: src.c: In function `test':
src.c:8: internal error--unrecognizable insn:
(insn 20 18 22 (set (reg:SI 85)
        (plus:SI (reg:SI 81)
            (const_int 32768))) -1 (nil)
    (nil))
../../gcc/toplev.c:1367: Internal compiler error in function fatal_insn

In some recompiled files, the game developers had to modify the code to work
around this bug, for example by storing a pointer to the array in a temporary
variable before indexing into it.


File: docs/decompiling_tutorial.md

This repository used to contain a tutorial for how to do
decompilation work in the repo.

It has been less useful as more and more was decompiled,
and also more of a chore to keep up-to-date, so it has been
removed from the repo.

It is still interesting for historical purposes or for
curiosity, you can find the last version of it in revision
9963e7f5d5fa8caee329f6b40e393d8a2c45390b.


File: docs/Documenting.md

Documentation Style Guide

This project uses Doxygen to generate documentation pages from comments found in the source files. This guide focuses on writing compatible comments and ensuring consistency across the codebase.

However to keep the documentation readable in text and favor consistency, the Doxygen commands that should be used are restricted to what this document mentions.

To generate a doxygen manual for the project, ensure you have doxygen installed and then cd into the project root directory and run doxygen Doxyfile.

The documentation can then be browsed by opening docs/doxygen/html/index.html in a web browser.

Documenting Functions

Any comments inside functions, except bugs (see below), should use //-style comments, even if spanning over multiple lines.

A simple example of documenting a function with just a description (note the leading /**):

c
/**
 * Update the crawl sound timer, and play the crawling sound when it reaches 0.
 */
void EnInsect_UpdateCrawlSfx(EnInsect* this) {

A more complete example:

c
/**
 * Request to either increase or consume magic.
 *
 * @param amount the positive-valued amount to either increase or decrease magic by
 * @param type how the magic is increased or consumed.
 *
 * @return false if the request failed
 */
s32 Magic_RequestChange(PlayState* play, s16 amount, s16 type) {

Note:

  • Documentation for self-explanatory arguments (@param) and return values (@return) may be omitted.
  • @param commands should not have empty lines in between.
  • Different commands (main description, @param, @return, ...) should be separated by empty lines.

Other directives that may be used for documenting functions:

  • @see to reference something else (see below).
  • @note to bring attention to some of the function behavior.

Documenting Variables

In case the name of a variable isn't completely clear, documentation can provide a description.

If applicable, it may refer to a set of defines or enumerations that should be used with it (those should be linked with @see, see below).

c
/**
 * My description of this variable
 */
s32 foo;

Documenting Files

File documentation should be located at the top of the file, above #includes.

File documentation should only feature information that is general to the file or the system it implements.

c
/**
 * @file z_fcurve_data_skelanime.c
 * @brief Curve skeleton animation system
 *
 * A curve skeleton has a fixed number of limbs, ...
...
 */

Other

Documenting Bugs:

Bugs should be documented on the line above where the bug begins.

c
//! @bug Missing early return

Bug described on multiple lines should still use the //! syntax, over multiple lines. For example:

c
//! @bug this code was clearly meaning to print `abs(camera->camDataIdx)` as a
//! one-or-two-digit number, instead of `i`.

@see should be used to provide links to related information where appropriate, for example:

c
/**
 * Sets the next framebuffer to the framebuffer associated to `task`.
 * If there is no current buffer or it is time to swap, this buffer will be swapped to
 * immediately, otherwise it will be swapped to later in Sched_HandleRetrace.
 *
 * @see Sched_HandleRetrace
 */
void Sched_SetNextFramebufferFromTask(Scheduler* sc, OSScTask* task) {

In the case of functions, @see should come before the first @param.

@see may also be used for documenting files or variables.

HTML and LaTeX

It is possible to include HTML and LaTeX in documentation comments.

However it is prefered not to do so, so that the raw text stays readable when looked at as plain text, for example when browsing the source code.


File: docs/libu64.md

libu64

This document explains the reasoning behind organizing the libu64 files.

libu64 is known about from the Animal Crossing (GameCube) map files.

Here is the relevant excerpt from the Doubutsu no Mori+ 1.0 map file (for .text):

text
/* Detailed source-code truncated for AI context efficiency. */

This repository's debug.c (formerly logutils.c), gfxprint.c and pad.c (formerly padutils.c) line up with the map.

Note debug.c has additional debug-only functions in gc-eu-mq-dbg, hinting that there were two versions of libu64, a debug version and a non-debug version.

Additionally debug.c, gfxprint.c and pad.c all require compilation flags -O2 (instead of -O2 -g3) to match, as supplementary evidence these were part of a separately compiled library.

-O2 is also required for most files between gfxprint.c and pad.c in the code segment (see spec), hinting that these other files (loadfragment2_n64.c, loadfragment2_gc.c, mtxuty-cvt.c, relocation_gc.c, load_gc.c, system_heap.c) are also part of libu64.

Files rcp_utils.c and logseverity_gc.c do not strictly require -O2, but they do match with -O2.

padsetup.c also requires -O2.

On the other hand, the function Overlay_Load (in loadfragment2_n64.c or load_gc.c depending on game version) calls DmaMgr_RequestSync, a function that is not part of libu64.
This could suggest these files are not part of libu64, but the other evidence detailed above seems stronger.
It is also a possibility that libu64 expected users to provide the function, and it would have been an undefined symbol in the library.

All in all this suggests all files in code between the audio code and libc64, are part of libu64.

In the OoT boot segment, stackcheck.c is right next to debug.c and requires -O2: this hints stackcheck.c could be part of libu64 too. This is confirmed by looking at Majora's Mask n64-us, where stackcheck.c is in the middle of other libu64 files in the boot segment (see MM spec).


File: docs/retail_versions.md

Decompiling retail versions

The next decompilation target for OOT is NTSC version 1.2
(ntsc-1.2), because it is the N64 version that is most similar to the GC
versions. Unfortunately there are still a lot of differences,
but once this version is done, future
N64 versions should be much easier, as the changes between N64 versions are
small in comparison.

Instead of cping a matching build into expected/, the target ROM is disassembled as .s files then
reassembled as .o files directly into expected/build/ntsc-1.2 for diff tools.
This allows us to make progress matching code in parallel with solving other
problems (such as the build system, ROM organization, and BSS ordering). The
files in tools/disasm/ntsc-1.2 say how to split the source files and where the
functions and variables are in the target ROM, and these may need to be updated
if there are mistakes or if function names change due to documentation work.

Unfortunately, the disassembly is not perfect, so a "correct" decompilation might
still show diffs with data symbols. We might improve this later, but these data
diffs are fine to ignore for now.

For register and stack allocation differences, often the code can be tweaked so
that it matches both the retail ROM while continuing to match GC versions and the Debug ROM (for
example, by reordering assignments or moving a local variable declaration inside
an if block). Since retail MM versions currently target N64, checking MM decomp for similar code can help.

We can handle code that is different between versions by adding
#if PLATFORM_N64 ... #endif or #if PLATFORM_GC ... #endif around these parts of the
code. In order to keep the code readable, we should try to minimize the amount of
#if noise whenever possible.

Setup

  1. Copy your target JP NTSC 1.2 ROM to baseroms/ntsc-1.2/baserom.z64

  2. Build the non-matching test ROM by running

    sh
    make setup -jN VERSION=ntsc-1.2
    make -jN VERSION=ntsc-1.2

    where N is the number of cores on your machine. This will build into
    build/ntsc-1.2 and produce build/ntsc-1.2/oot-ntsc-1.2.z64.

    If you later want to delete all output files, run

    sh
    make clean VERSION=ntsc-1.2
  3. Disassemble the target ROM by running

    sh
    make disasm VERSION=ntsc-1.2

    The outputs will be written to expected/build/ntsc-1.2.

    Note that if you need to copy a matching build for another version, you can use e.g.

    sh
    mkdir -p expected/build
    cp -r build/gc-eu-mq-dbg expected/build

    to avoid clobbering the disassembly.

Diff Tools

Note that many tools will require activating the Python virtual environment
in your terminal session. To do this, run:

sh
source .venv/bin/activate

retail_progress.py

Running ./retail_progress.py path/to/file.c will attempt to figure out which functions
in a file still need to match for ntsc-1.2. To get an overview of diffs for
all files, run ./retail_progress.py with no arguments.

asm-differ / diff.py

To diff assembly for a single function in ntsc-1.2, run e.g.

sh
./diff.py -mwo3 -v ntsc-1.2 Math3D_CylTriVsIntersect

The -v flag tells diff.py to compare between build/ntsc-1.2 and
expected/build/ntsc-1.2, and to use make VERSION=ntsc-1.2 when rebuilding.

You may also want to diff versions gc-eu-mq and/or gc-eu-mq-dbg in another terminal
to ensure any changes still match there.

Permuter and decomp.me

Disassembly for individual functions is written to
expected/build/ntsc-1.2/functions, so to get a decomp.me scratch you can run
e.g.

sh
decomp-permuter/import.py \
  src/code/sys_math3d.c \
  expected/build/ntsc-1.2/functions/src/code/sys_math3d/Math3D_CylTriVsIntersect.s \
  VERSION=ntsc-1.2 --decompme

2. Official Technical Reference & Guides (zeldaret/website)

ZeldaRET Website

This project was generated with Angular CLI version 12.2.10.

Development server

Run ng serve for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.

Code scaffolding

Run ng generate component component-name to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module.

Build

Run ng build to build the project. The build artifacts will be stored in the dist/ directory.

Running unit tests

Run ng test to execute the unit tests via Karma.

Running end-to-end tests

Run ng e2e to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.

Further help

To get more help on the Angular CLI use ng help or go check out the Angular CLI Overview and Command Reference page.