mirror of
https://github.com/zeldaret/oot.git
synced 2025-06-07 17:11:50 +00:00
Write about IDO and EGCS in compilers.md (#2432)
* Write about IDO and EGCS in compilers.md * Fix typo * Fix another typo * Apply suggestions from code review Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> --------- Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com>
This commit is contained in:
parent
284ecb114e
commit
11b7bf2914
4 changed files with 66 additions and 3 deletions
63
docs/compilers.md
Normal file
63
docs/compilers.md
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# 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"](https://en.wikipedia.org/wiki/SGI_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](https://github.com/n64decomp/qemu-irix) (now
|
||||||
|
unmaintained) to run emulate IRIX on modern systems, but nowadays we use the
|
||||||
|
more lightweight
|
||||||
|
[ido-static-recomp](https://github.com/decompals/ido-static-recomp) instead.
|
||||||
|
|
||||||
|
## EGCS
|
||||||
|
|
||||||
|
[EGCS (Experimental/Enhanced GNU Compiler System)](https://en.wikipedia.org/wiki/GNU_Compiler_Collection#EGCS_fork)
|
||||||
|
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](https://github.com/decompals/mips-gcc-egcs-2.91.66)
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
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.
|
|
@ -2570,7 +2570,7 @@ void Actor_Draw(PlayState* play, Actor* actor) {
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x06, play->objectCtx.slots[actor->objectSlot].segment);
|
gSPSegment(POLY_OPA_DISP++, 0x06, play->objectCtx.slots[actor->objectSlot].segment);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x06, play->objectCtx.slots[actor->objectSlot].segment);
|
gSPSegment(POLY_XLU_DISP++, 0x06, play->objectCtx.slots[actor->objectSlot].segment);
|
||||||
#else
|
#else
|
||||||
// Workaround for EGCS bug
|
// Workaround for EGCS internal compiler error (see docs/compilers.md)
|
||||||
slots = play->objectCtx.slots;
|
slots = play->objectCtx.slots;
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x06, slots[actor->objectSlot].segment);
|
gSPSegment(POLY_OPA_DISP++, 0x06, slots[actor->objectSlot].segment);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x06, slots[actor->objectSlot].segment);
|
gSPSegment(POLY_XLU_DISP++, 0x06, slots[actor->objectSlot].segment);
|
||||||
|
|
|
@ -119,7 +119,7 @@ void Font_LoadOrderedFont(Font* font) {
|
||||||
|
|
||||||
PRINTF("msg_data=%x, msg_data0=%x jj=%x\n", font->msgOffset, font->msgLength, len);
|
PRINTF("msg_data=%x, msg_data0=%x jj=%x\n", font->msgOffset, font->msgLength, len);
|
||||||
|
|
||||||
// Workaround for EGCS bug
|
// Workaround for EGCS internal compiler error (see docs/compilers.md)
|
||||||
msgBufWide = font->msgBufWide;
|
msgBufWide = font->msgBufWide;
|
||||||
fontBufIndex = 0;
|
fontBufIndex = 0;
|
||||||
for (codePointIndex = 0; msgBufWide[codePointIndex] != MESSAGE_WIDE_END; codePointIndex++) {
|
for (codePointIndex = 0; msgBufWide[codePointIndex] != MESSAGE_WIDE_END; codePointIndex++) {
|
||||||
|
|
|
@ -853,7 +853,7 @@ void Sram_InitSave(FileSelectState* fileSelect, SramContext* sramCtx) {
|
||||||
#if !PLATFORM_IQUE
|
#if !PLATFORM_IQUE
|
||||||
gSaveContext.save.info.playerData.playerName[offset] = fileSelect->fileNames[fileSelect->buttonIndex][offset];
|
gSaveContext.save.info.playerData.playerName[offset] = fileSelect->fileNames[fileSelect->buttonIndex][offset];
|
||||||
#else
|
#else
|
||||||
// Workaround for EGCS bug
|
// Workaround for EGCS internal compiler error (see docs/compilers.md)
|
||||||
u8* fileName = fileSelect->fileNames[fileSelect->buttonIndex];
|
u8* fileName = fileSelect->fileNames[fileSelect->buttonIndex];
|
||||||
|
|
||||||
gSaveContext.save.info.playerData.playerName[offset] = fileName[offset];
|
gSaveContext.save.info.playerData.playerName[offset] = fileName[offset];
|
||||||
|
|
Loading…
Add table
Reference in a new issue