1
0
mirror of https://github.com/blawar/ooot.git synced 2024-07-04 18:13:37 +00:00

removed unused files

This commit is contained in:
Blake Warner 2022-03-03 08:26:31 -05:00
parent 91ca095d29
commit ebe5cae136
93 changed files with 0 additions and 22750 deletions

View File

@ -1,30 +0,0 @@
FROM ubuntu:21.10 as build
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
apt-get update && \
apt-get install -y \
binutils-mips-linux-gnu \
build-essential \
pkg-config \
python3 \
python3-pip \
git \
wget \
unzip \
clang-tidy \
clang-format \
libpng-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN python3 -m pip install --user colorama ansiwrap attrs watchdog python-Levenshtein
RUN python3 -m pip install --upgrade attrs pycparser
ENV LANG C.UTF-8
RUN mkdir /oot
WORKDIR /oot
CMD ["/bin/sh", "-c", \
"echo 'usage:\n docker run --rm --mount type=bind,source=\"$(pwd)\",destination=/oot oot make -j$(nproc) setup\n docker run --rm --mount type=bind,source=\"$(pwd)\",destination=/oot oot make -j$(nproc)'"]

2494
Doxyfile

File diff suppressed because it is too large Load Diff

68
Jenkinsfile vendored
View File

@ -1,68 +0,0 @@
pipeline {
agent {
label 'oot'
}
stages {
stage('Check for unused asm') {
steps {
sh './tools/find_unused_asm.sh'
}
}
stage('Setup') {
steps {
sh 'cp /usr/local/etc/roms/baserom_oot.z64 baserom_original.z64'
sh 'make -j setup'
}
}
stage('Build (qemu-irix)') {
when {
branch 'master'
}
steps {
sh 'ORIG_COMPILER=1 make -j'
}
}
stage('Build') {
when {
not {
branch 'master'
}
}
steps {
sh 'make -j'
}
}
stage('Report Progress') {
when {
branch 'master'
}
steps {
sh 'mkdir reports'
sh 'python3 progress.py csv >> reports/progress-oot-nonmatching.csv'
sh 'python3 progress.py csv -m >> reports/progress-oot-matching.csv'
sh 'python3 progress.py shield-json > reports/progress-oot-shield.json'
stash includes: 'reports/*', name: 'reports'
}
}
stage('Update Progress') {
when {
branch 'master'
}
agent {
label 'master'
}
steps {
unstash 'reports'
sh 'cat reports/progress-oot-nonmatching.csv >> /var/www/zelda64.dev/assets/csv/progress-oot-nonmatching.csv'
sh 'cat reports/progress-oot-matching.csv >> /var/www/zelda64.dev/assets/csv/progress-oot-matching.csv'
sh 'cat reports/progress-oot-shield.json > /var/www/zelda64.dev/assets/csv/progress-oot-shield.json'
}
}
}
post {
always {
cleanWs()
}
}
}

View File

@ -1,41 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osDisableInt
/* 007E80 80007280 3C0A8001 */ lui $t2, %hi(__OSGlobalIntMask) # $t2, 0x8001
/* 007E84 80007284 254AAD00 */ addiu $t2, %lo(__OSGlobalIntMask) # addiu $t2, $t2, -0x5300
/* 007E88 80007288 8D4B0000 */ lw $t3, ($t2)
/* 007E8C 8000728C 316BFF00 */ andi $t3, $t3, 0xff00
/* 007E90 80007290 40086000 */ mfc0 $t0, $12
/* 007E94 80007294 2401FFFE */ li $at, -2
/* 007E98 80007298 01014824 */ and $t1, $t0, $at
/* 007E9C 8000729C 40896000 */ mtc0 $t1, $12
/* 007EA0 800072A0 31020001 */ andi $v0, $t0, 1
/* 007EA4 800072A4 8D480000 */ lw $t0, ($t2)
/* 007EA8 800072A8 3108FF00 */ andi $t0, $t0, 0xff00
/* 007EAC 800072AC 110B000E */ beq $t0, $t3, .L800072E8
/* 007EB0 800072B0 3C0A8001 */ lui $t2, %hi(__osRunningThread) # $t2, 0x8001
/* 007EB4 800072B4 254AAD50 */ addiu $t2, %lo(__osRunningThread) # addiu $t2, $t2, -0x52b0
/* 007EB8 800072B8 8D490118 */ lw $t1, 0x118($t2)
/* 007EBC 800072BC 312AFF00 */ andi $t2, $t1, 0xff00
/* 007EC0 800072C0 01485024 */ and $t2, $t2, $t0
/* 007EC4 800072C4 3C01FFFF */ lui $at, (0xFFFF00FF >> 16) # lui $at, 0xffff
/* 007EC8 800072C8 342100FF */ ori $at, (0xFFFF00FF & 0xFFFF) # ori $at, $at, 0xff
/* 007ECC 800072CC 01214824 */ and $t1, $t1, $at
/* 007ED0 800072D0 012A4825 */ or $t1, $t1, $t2
/* 007ED4 800072D4 2401FFFE */ li $at, -2
/* 007ED8 800072D8 01214824 */ and $t1, $t1, $at
/* 007EDC 800072DC 40896000 */ mtc0 $t1, $12
/* 007EE0 800072E0 00000000 */ nop
/* 007EE4 800072E4 00000000 */ nop
.L800072E8:
/* 007EE8 800072E8 03E00008 */ jr $ra
/* 007EEC 800072EC 00000000 */ nop

View File

@ -1,15 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osGetCause
/* 008790 80007B90 40026800 */ mfc0 $v0, $13
/* 008794 80007B94 03E00008 */ jr $ra
/* 008798 80007B98 00000000 */ nop

View File

@ -1,15 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osGetFpcCsr
/* 008680 80007A80 4442F800 */ cfc1 $v0, $31
/* 008684 80007A84 03E00008 */ jr $ra
/* 008688 80007A88 00000000 */ nop

View File

@ -1,15 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osGetSR
/* 0052B0 800046B0 40026000 */ mfc0 $v0, $12
/* 0052B4 800046B4 03E00008 */ jr $ra
/* 0052B8 800046B8 00000000 */ nop

View File

@ -1,62 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osProbeTLB
/* 005C40 80005040 40085000 */ mfc0 $t0, $10
/* 005C44 80005044 310900FF */ andi $t1, $t0, 0xff
/* 005C48 80005048 2401E000 */ li $at, -8192
/* 005C4C 8000504C 00815024 */ and $t2, $a0, $at
/* 005C50 80005050 012A4825 */ or $t1, $t1, $t2
/* 005C54 80005054 40895000 */ mtc0 $t1, $10
/* 005C58 80005058 00000000 */ nop
/* 005C5C 8000505C 00000000 */ nop
/* 005C60 80005060 00000000 */ nop
/* 005C64 80005064 42000008 */ tlbp
/* 005C68 80005068 00000000 */ nop
/* 005C6C 8000506C 00000000 */ nop
/* 005C70 80005070 400B0000 */ mfc0 $t3, $0
/* 005C74 80005074 3C018000 */ lui $at, 0x8000
/* 005C78 80005078 01615824 */ and $t3, $t3, $at
/* 005C7C 8000507C 1560001A */ bnez $t3, .L800050E8
/* 005C80 80005080 00000000 */ nop
/* 005C84 80005084 42000001 */ tlbr
/* 005C88 80005088 00000000 */ nop
/* 005C8C 8000508C 00000000 */ nop
/* 005C90 80005090 00000000 */ nop
/* 005C94 80005094 400B2800 */ mfc0 $t3, $5
/* 005C98 80005098 216B2000 */ addi $t3, $t3, 0x2000
/* 005C9C 8000509C 000B5842 */ srl $t3, $t3, 1
/* 005CA0 800050A0 01646024 */ and $t4, $t3, $a0
/* 005CA4 800050A4 15800004 */ bnez $t4, .L800050B8
/* 005CA8 800050A8 216BFFFF */ addi $t3, $t3, -1
/* 005CAC 800050AC 40021000 */ mfc0 $v0, $2
/* 005CB0 800050B0 10000002 */ b .L800050BC
/* 005CB4 800050B4 00000000 */ nop
.L800050B8:
/* 005CB8 800050B8 40021800 */ mfc0 $v0, $3
.L800050BC:
/* 005CBC 800050BC 304D0002 */ andi $t5, $v0, 2
/* 005CC0 800050C0 11A00009 */ beqz $t5, .L800050E8
/* 005CC4 800050C4 00000000 */ nop
/* 005CC8 800050C8 3C013FFF */ lui $at, (0x3FFFFFC0 >> 16) # lui $at, 0x3fff
/* 005CCC 800050CC 3421FFC0 */ ori $at, (0x3FFFFFC0 & 0xFFFF) # ori $at, $at, 0xffc0
/* 005CD0 800050D0 00411024 */ and $v0, $v0, $at
/* 005CD4 800050D4 00021180 */ sll $v0, $v0, 6
/* 005CD8 800050D8 008B6824 */ and $t5, $a0, $t3
/* 005CDC 800050DC 004D1020 */ add $v0, $v0, $t5
/* 005CE0 800050E0 10000002 */ b .L800050EC
/* 005CE4 800050E4 00000000 */ nop
.L800050E8:
/* 005CE8 800050E8 2402FFFF */ li $v0, -1
.L800050EC:
/* 005CEC 800050EC 40885000 */ mtc0 $t0, $10
/* 005CF0 800050F0 03E00008 */ jr $ra
/* 005CF4 800050F4 00000000 */ nop

View File

@ -1,19 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osRestoreInt
/* 007EF0 800072F0 40086000 */ mfc0 $t0, $12
/* 007EF4 800072F4 01044025 */ or $t0, $t0, $a0
/* 007EF8 800072F8 40886000 */ mtc0 $t0, $12
/* 007EFC 800072FC 00000000 */ nop
/* 007F00 80007300 00000000 */ nop
/* 007F04 80007304 03E00008 */ jr $ra
/* 007F08 80007308 00000000 */ nop

View File

@ -1,15 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osSetCompare
/* 007B00 80006F00 40845800 */ mtc0 $a0, $11
/* 007B04 80006F04 03E00008 */ jr $ra
/* 007B08 80006F08 00000000 */ nop

View File

@ -1,16 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osSetFpcCsr
/* 008670 80007A70 4442F800 */ cfc1 $v0, $31
/* 008674 80007A74 44C4F800 */ ctc1 $a0, $31
/* 008678 80007A78 03E00008 */ jr $ra
/* 00867C 80007A7C 00000000 */ nop

View File

@ -1,16 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osSetSR
/* 0052A0 800046A0 40846000 */ mtc0 $a0, $12
/* 0052A4 800046A4 00000000 */ nop
/* 0052A8 800046A8 03E00008 */ jr $ra
/* 0052AC 800046AC 00000000 */ nop

View File

@ -1,16 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel __osSetWatchLo
/* 009F10 80009310 40849000 */ mtc0 $a0, $18
/* 009F14 80009314 00000000 */ nop
/* 009F18 80009318 03E00008 */ jr $ra
/* 009F1C 8000931C 00000000 */ nop

View File

@ -1,94 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel bcmp
/* 0074C0 800068C0 28C10010 */ slti $at, $a2, 0x10
/* 0074C4 800068C4 14200037 */ bnez $at, .bytecmp
/* 0074C8 800068C8 00851026 */ xor $v0, $a0, $a1
/* 0074CC 800068CC 30420003 */ andi $v0, $v0, 3
/* 0074D0 800068D0 14400019 */ bnez $v0, .unalgncmp
/* 0074D4 800068D4 0004C023 */ negu $t8, $a0
/* 0074D8 800068D8 33180003 */ andi $t8, $t8, 3
/* 0074DC 800068DC 13000007 */ beqz $t8, .wordcmp
/* 0074E0 800068E0 00D83023 */ subu $a2, $a2, $t8
/* 0074E4 800068E4 00601025 */ move $v0, $v1
/* 0074E8 800068E8 88820000 */ lwl $v0, ($a0)
/* 0074EC 800068EC 88A30000 */ lwl $v1, ($a1)
/* 0074F0 800068F0 00982021 */ addu $a0, $a0, $t8
/* 0074F4 800068F4 00B82821 */ addu $a1, $a1, $t8
/* 0074F8 800068F8 14430036 */ bne $v0, $v1, .cmpdone
.wordcmp:
/* 0074FC 800068FC 2401FFFC */ li $at, -4
/* 007500 80006900 00C13824 */ and $a3, $a2, $at
/* 007504 80006904 10E00027 */ beqz $a3, .bytecmp
/* 007508 80006908 00C73023 */ subu $a2, $a2, $a3
/* 00750C 8000690C 00E43821 */ addu $a3, $a3, $a0
/* 007510 80006910 8C820000 */ lw $v0, ($a0)
.L80006914:
/* 007514 80006914 8CA30000 */ lw $v1, ($a1)
/* 007518 80006918 24840004 */ addiu $a0, $a0, 4
/* 00751C 8000691C 24A50004 */ addiu $a1, $a1, 4
/* 007520 80006920 1443002C */ bne $v0, $v1, .cmpdone
/* 007524 80006924 00000000 */ nop
/* 007528 80006928 5487FFFA */ bnel $a0, $a3, .L80006914
/* 00752C 8000692C 8C820000 */ lw $v0, ($a0)
/* 007530 80006930 1000001C */ b .bytecmp
/* 007534 80006934 00000000 */ nop
.unalgncmp:
/* 007538 80006938 00053823 */ negu $a3, $a1
/* 00753C 8000693C 30E70003 */ andi $a3, $a3, 3
/* 007540 80006940 10E0000A */ beqz $a3, .partaligncmp
/* 007544 80006944 00C73023 */ subu $a2, $a2, $a3
/* 007548 80006948 00E43821 */ addu $a3, $a3, $a0
/* 00754C 8000694C 90820000 */ lbu $v0, ($a0)
.L80006950:
/* 007550 80006950 90A30000 */ lbu $v1, ($a1)
/* 007554 80006954 24840001 */ addiu $a0, $a0, 1
/* 007558 80006958 24A50001 */ addiu $a1, $a1, 1
/* 00755C 8000695C 1443001D */ bne $v0, $v1, .cmpdone
/* 007560 80006960 00000000 */ nop
/* 007564 80006964 5487FFFA */ bnel $a0, $a3, .L80006950
/* 007568 80006968 90820000 */ lbu $v0, ($a0)
.partaligncmp:
/* 00756C 8000696C 2401FFFC */ li $at, -4
/* 007570 80006970 00C13824 */ and $a3, $a2, $at
/* 007574 80006974 10E0000B */ beqz $a3, .bytecmp
/* 007578 80006978 00C73023 */ subu $a2, $a2, $a3
/* 00757C 8000697C 00E43821 */ addu $a3, $a3, $a0
/* 007580 80006980 88820000 */ lwl $v0, ($a0)
.L80006984:
/* 007584 80006984 8CA30000 */ lw $v1, ($a1)
/* 007588 80006988 98820003 */ lwr $v0, 3($a0)
/* 00758C 8000698C 24840004 */ addiu $a0, $a0, 4
/* 007590 80006990 24A50004 */ addiu $a1, $a1, 4
/* 007594 80006994 1443000F */ bne $v0, $v1, .cmpdone
/* 007598 80006998 00000000 */ nop
/* 00759C 8000699C 5487FFF9 */ bnel $a0, $a3, .L80006984
/* 0075A0 800069A0 88820000 */ lwl $v0, ($a0)
.bytecmp:
/* 0075A4 800069A4 18C00009 */ blez $a2, .L800069CC
/* 0075A8 800069A8 00C43821 */ addu $a3, $a2, $a0
/* 0075AC 800069AC 90820000 */ lbu $v0, ($a0)
.L800069B0:
/* 0075B0 800069B0 90A30000 */ lbu $v1, ($a1)
/* 0075B4 800069B4 24840001 */ addiu $a0, $a0, 1
/* 0075B8 800069B8 24A50001 */ addiu $a1, $a1, 1
/* 0075BC 800069BC 14430005 */ bne $v0, $v1, .cmpdone
/* 0075C0 800069C0 00000000 */ nop
/* 0075C4 800069C4 5487FFFA */ bnel $a0, $a3, .L800069B0
/* 0075C8 800069C8 90820000 */ lbu $v0, ($a0)
.L800069CC:
/* 0075CC 800069CC 03E00008 */ jr $ra
/* 0075D0 800069D0 00001025 */ move $v0, $zero
.cmpdone:
/* 0075D4 800069D4 03E00008 */ jr $ra
/* 0075D8 800069D8 24020001 */ li $v0, 1

View File

@ -1,230 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel bcopy
/* 007B10 80006F10 10C0001A */ beqz $a2, ret
/* 007B14 80006F14 00A03825 */ move $a3, $a1
/* 007B18 80006F18 10850018 */ beq $a0, $a1, ret
/* 007B1C 80006F1C 00A4082A */ slt $at, $a1, $a0
/* 007B20 80006F20 54200008 */ bnezl $at, goforwards
/* 007B24 80006F24 28C10010 */ slti $at, $a2, 0x10
/* 007B28 80006F28 00861020 */ add $v0, $a0, $a2
/* 007B2C 80006F2C 00A2082A */ slt $at, $a1, $v0
/* 007B30 80006F30 50200004 */ beql $at, $zero, goforwards
/* 007B34 80006F34 28C10010 */ slti $at, $a2, 0x10
/* 007B38 80006F38 1000005B */ b gobackwards
/* 007B3C 80006F3C 28C10010 */ slti $at, $a2, 0x10
/* 007B40 80006F40 28C10010 */ slti $at, $a2, 0x10
goforwards:
/* 007B44 80006F44 14200005 */ bnez $at, forwards_bytecopy
/* 007B48 80006F48 00000000 */ nop
/* 007B4C 80006F4C 30820003 */ andi $v0, $a0, 3
/* 007B50 80006F50 30A30003 */ andi $v1, $a1, 3
/* 007B54 80006F54 1043000B */ beq $v0, $v1, forwalignable
/* 007B58 80006F58 00000000 */ nop
forwards_bytecopy:
/* 007B5C 80006F5C 10C00007 */ beqz $a2, ret
/* 007B60 80006F60 00000000 */ nop
/* 007B64 80006F64 00861821 */ addu $v1, $a0, $a2
.L80006F68:
/* 007B68 80006F68 80820000 */ lb $v0, ($a0)
/* 007B6C 80006F6C 24840001 */ addiu $a0, $a0, 1
/* 007B70 80006F70 24A50001 */ addiu $a1, $a1, 1
/* 007B74 80006F74 1483FFFC */ bne $a0, $v1, .L80006F68
/* 007B78 80006F78 A0A2FFFF */ sb $v0, -1($a1)
ret:
/* 007B7C 80006F7C 03E00008 */ jr $ra
/* 007B80 80006F80 00E01025 */ move $v0, $a3
forwalignable:
/* 007B84 80006F84 10400018 */ beqz $v0, forwards_32
/* 007B88 80006F88 24010001 */ li $at, 1
/* 007B8C 80006F8C 1041000F */ beq $v0, $at, forw_copy3
/* 007B90 80006F90 24010002 */ li $at, 2
/* 007B94 80006F94 50410008 */ beql $v0, $at, forw_copy2
/* 007B98 80006F98 84820000 */ lh $v0, ($a0)
/* 007B9C 80006F9C 80820000 */ lb $v0, ($a0)
/* 007BA0 80006FA0 24840001 */ addiu $a0, $a0, 1
/* 007BA4 80006FA4 24A50001 */ addiu $a1, $a1, 1
/* 007BA8 80006FA8 24C6FFFF */ addiu $a2, $a2, -1
/* 007BAC 80006FAC 1000000E */ b forwards_32
/* 007BB0 80006FB0 A0A2FFFF */ sb $v0, -1($a1)
/* 007BB4 80006FB4 84820000 */ lh $v0, ($a0)
forw_copy2:
/* 007BB8 80006FB8 24840002 */ addiu $a0, $a0, 2
/* 007BBC 80006FBC 24A50002 */ addiu $a1, $a1, 2
/* 007BC0 80006FC0 24C6FFFE */ addiu $a2, $a2, -2
/* 007BC4 80006FC4 10000008 */ b forwards_32
/* 007BC8 80006FC8 A4A2FFFE */ sh $v0, -2($a1)
forw_copy3:
/* 007BCC 80006FCC 80820000 */ lb $v0, ($a0)
/* 007BD0 80006FD0 84830001 */ lh $v1, 1($a0)
/* 007BD4 80006FD4 24840003 */ addiu $a0, $a0, 3
/* 007BD8 80006FD8 24A50003 */ addiu $a1, $a1, 3
/* 007BDC 80006FDC 24C6FFFD */ addiu $a2, $a2, -3
/* 007BE0 80006FE0 A0A2FFFD */ sb $v0, -3($a1)
/* 007BE4 80006FE4 A4A3FFFE */ sh $v1, -2($a1)
forwards_32:
/* 007BE8 80006FE8 28C10020 */ slti $at, $a2, 0x20
/* 007BEC 80006FEC 54200016 */ bnezl $at, .L80007048
/* 007BF0 80006FF0 28C10010 */ slti $at, $a2, 0x10
/* 007BF4 80006FF4 8C820000 */ lw $v0, ($a0)
/* 007BF8 80006FF8 8C830004 */ lw $v1, 4($a0)
/* 007BFC 80006FFC 8C880008 */ lw $t0, 8($a0)
/* 007C00 80007000 8C89000C */ lw $t1, 0xc($a0)
/* 007C04 80007004 8C8A0010 */ lw $t2, 0x10($a0)
/* 007C08 80007008 8C8B0014 */ lw $t3, 0x14($a0)
/* 007C0C 8000700C 8C8C0018 */ lw $t4, 0x18($a0)
/* 007C10 80007010 8C8D001C */ lw $t5, 0x1c($a0)
/* 007C14 80007014 24840020 */ addiu $a0, $a0, 0x20
/* 007C18 80007018 24A50020 */ addiu $a1, $a1, 0x20
/* 007C1C 8000701C 24C6FFE0 */ addiu $a2, $a2, -0x20
/* 007C20 80007020 ACA2FFE0 */ sw $v0, -0x20($a1)
/* 007C24 80007024 ACA3FFE4 */ sw $v1, -0x1c($a1)
/* 007C28 80007028 ACA8FFE8 */ sw $t0, -0x18($a1)
/* 007C2C 8000702C ACA9FFEC */ sw $t1, -0x14($a1)
/* 007C30 80007030 ACAAFFF0 */ sw $t2, -0x10($a1)
/* 007C34 80007034 ACABFFF4 */ sw $t3, -0xc($a1)
/* 007C38 80007038 ACACFFF8 */ sw $t4, -8($a1)
/* 007C3C 8000703C 1000FFEA */ b forwards_32
/* 007C40 80007040 ACADFFFC */ sw $t5, -4($a1)
forwards_16:
/* 007C44 80007044 28C10010 */ slti $at, $a2, 0x10
.L80007048:
/* 007C48 80007048 5420000E */ bnezl $at, .L80007084
/* 007C4C 8000704C 28C10004 */ slti $at, $a2, 4
/* 007C50 80007050 8C820000 */ lw $v0, ($a0)
/* 007C54 80007054 8C830004 */ lw $v1, 4($a0)
/* 007C58 80007058 8C880008 */ lw $t0, 8($a0)
/* 007C5C 8000705C 8C89000C */ lw $t1, 0xc($a0)
/* 007C60 80007060 24840010 */ addiu $a0, $a0, 0x10
/* 007C64 80007064 24A50010 */ addiu $a1, $a1, 0x10
/* 007C68 80007068 24C6FFF0 */ addiu $a2, $a2, -0x10
/* 007C6C 8000706C ACA2FFF0 */ sw $v0, -0x10($a1)
/* 007C70 80007070 ACA3FFF4 */ sw $v1, -0xc($a1)
/* 007C74 80007074 ACA8FFF8 */ sw $t0, -8($a1)
/* 007C78 80007078 1000FFF2 */ b forwards_16
/* 007C7C 8000707C ACA9FFFC */ sw $t1, -4($a1)
forwards_4:
/* 007C80 80007080 28C10004 */ slti $at, $a2, 4
.L80007084:
/* 007C84 80007084 1420FFB5 */ bnez $at, forwards_bytecopy
/* 007C88 80007088 00000000 */ nop
/* 007C8C 8000708C 8C820000 */ lw $v0, ($a0)
/* 007C90 80007090 24840004 */ addiu $a0, $a0, 4
/* 007C94 80007094 24A50004 */ addiu $a1, $a1, 4
/* 007C98 80007098 24C6FFFC */ addiu $a2, $a2, -4
/* 007C9C 8000709C 1000FFF8 */ b forwards_4
/* 007CA0 800070A0 ACA2FFFC */ sw $v0, -4($a1)
/* 007CA4 800070A4 28C10010 */ slti $at, $a2, 0x10
gobackwards:
/* 007CA8 800070A8 00862020 */ add $a0, $a0, $a2
/* 007CAC 800070AC 14200005 */ bnez $at, backwards_bytecopy
/* 007CB0 800070B0 00A62820 */ add $a1, $a1, $a2
/* 007CB4 800070B4 30820003 */ andi $v0, $a0, 3
/* 007CB8 800070B8 30A30003 */ andi $v1, $a1, 3
/* 007CBC 800070BC 1043000D */ beq $v0, $v1, backalignable
/* 007CC0 800070C0 00000000 */ nop
backwards_bytecopy:
/* 007CC4 800070C4 10C0FFAD */ beqz $a2, ret
/* 007CC8 800070C8 00000000 */ nop
/* 007CCC 800070CC 2484FFFF */ addiu $a0, $a0, -1
/* 007CD0 800070D0 24A5FFFF */ addiu $a1, $a1, -1
/* 007CD4 800070D4 00861823 */ subu $v1, $a0, $a2
.L800070D8:
/* 007CD8 800070D8 80820000 */ lb $v0, ($a0)
/* 007CDC 800070DC 2484FFFF */ addiu $a0, $a0, -1
/* 007CE0 800070E0 24A5FFFF */ addiu $a1, $a1, -1
/* 007CE4 800070E4 1483FFFC */ bne $a0, $v1, .L800070D8
/* 007CE8 800070E8 A0A20001 */ sb $v0, 1($a1)
/* 007CEC 800070EC 03E00008 */ jr $ra
/* 007CF0 800070F0 00E01025 */ move $v0, $a3
backalignable:
/* 007CF4 800070F4 10400018 */ beqz $v0, backwards_32
/* 007CF8 800070F8 24010003 */ li $at, 3
/* 007CFC 800070FC 1041000F */ beq $v0, $at, back_copy3
/* 007D00 80007100 24010002 */ li $at, 2
/* 007D04 80007104 50410008 */ beql $v0, $at, back_copy2
/* 007D08 80007108 8482FFFE */ lh $v0, -2($a0)
/* 007D0C 8000710C 8082FFFF */ lb $v0, -1($a0)
/* 007D10 80007110 2484FFFF */ addiu $a0, $a0, -1
/* 007D14 80007114 24A5FFFF */ addiu $a1, $a1, -1
/* 007D18 80007118 24C6FFFF */ addiu $a2, $a2, -1
/* 007D1C 8000711C 1000000E */ b backwards_32
/* 007D20 80007120 A0A20000 */ sb $v0, ($a1)
/* 007D24 80007124 8482FFFE */ lh $v0, -2($a0)
back_copy2:
/* 007D28 80007128 2484FFFE */ addiu $a0, $a0, -2
/* 007D2C 8000712C 24A5FFFE */ addiu $a1, $a1, -2
/* 007D30 80007130 24C6FFFE */ addiu $a2, $a2, -2
/* 007D34 80007134 10000008 */ b backwards_32
/* 007D38 80007138 A4A20000 */ sh $v0, ($a1)
back_copy3:
/* 007D3C 8000713C 8082FFFF */ lb $v0, -1($a0)
/* 007D40 80007140 8483FFFD */ lh $v1, -3($a0)
/* 007D44 80007144 2484FFFD */ addiu $a0, $a0, -3
/* 007D48 80007148 24A5FFFD */ addiu $a1, $a1, -3
/* 007D4C 8000714C 24C6FFFD */ addiu $a2, $a2, -3
/* 007D50 80007150 A0A20002 */ sb $v0, 2($a1)
/* 007D54 80007154 A4A30000 */ sh $v1, ($a1)
backwards_32:
/* 007D58 80007158 28C10020 */ slti $at, $a2, 0x20
/* 007D5C 8000715C 54200016 */ bnezl $at, .L800071B8
/* 007D60 80007160 28C10010 */ slti $at, $a2, 0x10
/* 007D64 80007164 8C82FFFC */ lw $v0, -4($a0)
/* 007D68 80007168 8C83FFF8 */ lw $v1, -8($a0)
/* 007D6C 8000716C 8C88FFF4 */ lw $t0, -0xc($a0)
/* 007D70 80007170 8C89FFF0 */ lw $t1, -0x10($a0)
/* 007D74 80007174 8C8AFFEC */ lw $t2, -0x14($a0)
/* 007D78 80007178 8C8BFFE8 */ lw $t3, -0x18($a0)
/* 007D7C 8000717C 8C8CFFE4 */ lw $t4, -0x1c($a0)
/* 007D80 80007180 8C8DFFE0 */ lw $t5, -0x20($a0)
/* 007D84 80007184 2484FFE0 */ addiu $a0, $a0, -0x20
/* 007D88 80007188 24A5FFE0 */ addiu $a1, $a1, -0x20
/* 007D8C 8000718C 24C6FFE0 */ addiu $a2, $a2, -0x20
/* 007D90 80007190 ACA2001C */ sw $v0, 0x1c($a1)
/* 007D94 80007194 ACA30018 */ sw $v1, 0x18($a1)
/* 007D98 80007198 ACA80014 */ sw $t0, 0x14($a1)
/* 007D9C 8000719C ACA90010 */ sw $t1, 0x10($a1)
/* 007DA0 800071A0 ACAA000C */ sw $t2, 0xc($a1)
/* 007DA4 800071A4 ACAB0008 */ sw $t3, 8($a1)
/* 007DA8 800071A8 ACAC0004 */ sw $t4, 4($a1)
/* 007DAC 800071AC 1000FFEA */ b backwards_32
/* 007DB0 800071B0 ACAD0000 */ sw $t5, ($a1)
backwards_16:
/* 007DB4 800071B4 28C10010 */ slti $at, $a2, 0x10
.L800071B8:
/* 007DB8 800071B8 5420000E */ bnezl $at, .L800071F4
/* 007DBC 800071BC 28C10004 */ slti $at, $a2, 4
/* 007DC0 800071C0 8C82FFFC */ lw $v0, -4($a0)
/* 007DC4 800071C4 8C83FFF8 */ lw $v1, -8($a0)
/* 007DC8 800071C8 8C88FFF4 */ lw $t0, -0xc($a0)
/* 007DCC 800071CC 8C89FFF0 */ lw $t1, -0x10($a0)
/* 007DD0 800071D0 2484FFF0 */ addiu $a0, $a0, -0x10
/* 007DD4 800071D4 24A5FFF0 */ addiu $a1, $a1, -0x10
/* 007DD8 800071D8 24C6FFF0 */ addiu $a2, $a2, -0x10
/* 007DDC 800071DC ACA2000C */ sw $v0, 0xc($a1)
/* 007DE0 800071E0 ACA30008 */ sw $v1, 8($a1)
/* 007DE4 800071E4 ACA80004 */ sw $t0, 4($a1)
/* 007DE8 800071E8 1000FFF2 */ b backwards_16
/* 007DEC 800071EC ACA90000 */ sw $t1, ($a1)
backwards_4:
/* 007DF0 800071F0 28C10004 */ slti $at, $a2, 4
.L800071F4:
/* 007DF4 800071F4 1420FFB3 */ bnez $at, backwards_bytecopy
/* 007DF8 800071F8 00000000 */ nop
/* 007DFC 800071FC 8C82FFFC */ lw $v0, -4($a0)
/* 007E00 80007200 2484FFFC */ addiu $a0, $a0, -4
/* 007E04 80007204 24A5FFFC */ addiu $a1, $a1, -4
/* 007E08 80007208 24C6FFFC */ addiu $a2, $a2, -4
/* 007E0C 8000720C 1000FFF8 */ b backwards_4
/* 007E10 80007210 ACA20000 */ sw $v0, ($a1)

View File

@ -1,84 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel bzero
/* 005050 80004450 28A1000C */ slti $at, $a1, 0xc
/* 005054 80004454 1420001D */ bnez $at, .bytezero
/* 005058 80004458 00041823 */ negu $v1, $a0
/* 00505C 8000445C 30630003 */ andi $v1, $v1, 3
/* 005060 80004460 10600003 */ beqz $v1, .blkzero
/* 005064 80004464 00A32823 */ subu $a1, $a1, $v1
/* 005068 80004468 A8800000 */ swl $zero, ($a0)
/* 00506C 8000446C 00832021 */ addu $a0, $a0, $v1
.blkzero:
/* 005070 80004470 2401FFE0 */ li $at, -32
/* 005074 80004474 00A13824 */ and $a3, $a1, $at
/* 005078 80004478 10E0000C */ beqz $a3, .wordzero
/* 00507C 8000447C 00A72823 */ subu $a1, $a1, $a3
/* 005080 80004480 00E43821 */ addu $a3, $a3, $a0
.L80004484:
/* 005084 80004484 24840020 */ addiu $a0, $a0, 0x20
/* 005088 80004488 AC80FFE0 */ sw $zero, -0x20($a0)
/* 00508C 8000448C AC80FFE4 */ sw $zero, -0x1c($a0)
/* 005090 80004490 AC80FFE8 */ sw $zero, -0x18($a0)
/* 005094 80004494 AC80FFEC */ sw $zero, -0x14($a0)
/* 005098 80004498 AC80FFF0 */ sw $zero, -0x10($a0)
/* 00509C 8000449C AC80FFF4 */ sw $zero, -0xc($a0)
/* 0050A0 800044A0 AC80FFF8 */ sw $zero, -8($a0)
/* 0050A4 800044A4 1487FFF7 */ bne $a0, $a3, .L80004484
/* 0050A8 800044A8 AC80FFFC */ sw $zero, -4($a0)
.wordzero:
/* 0050AC 800044AC 2401FFFC */ li $at, -4
/* 0050B0 800044B0 00A13824 */ and $a3, $a1, $at
/* 0050B4 800044B4 10E00005 */ beqz $a3, .bytezero
/* 0050B8 800044B8 00A72823 */ subu $a1, $a1, $a3
/* 0050BC 800044BC 00E43821 */ addu $a3, $a3, $a0
.L800044C0:
/* 0050C0 800044C0 24840004 */ addiu $a0, $a0, 4
/* 0050C4 800044C4 1487FFFE */ bne $a0, $a3, .L800044C0
/* 0050C8 800044C8 AC80FFFC */ sw $zero, -4($a0)
.bytezero:
/* 0050CC 800044CC 18A00005 */ blez $a1, .zerodone
/* 0050D0 800044D0 00000000 */ nop
/* 0050D4 800044D4 00A42821 */ addu $a1, $a1, $a0
.L800044D8:
/* 0050D8 800044D8 24840001 */ addiu $a0, $a0, 1
/* 0050DC 800044DC 1485FFFE */ bne $a0, $a1, .L800044D8
/* 0050E0 800044E0 A080FFFF */ sb $zero, -1($a0)
.zerodone:
/* 0050E4 800044E4 03E00008 */ jr $ra
/* 0050E8 800044E8 00000000 */ nop
/* 0050EC 800044EC 00000000 */ nop
/* 0050F0 800044F0 00000000 */ nop
/* 0050F4 800044F4 00000000 */ nop
/* 0050F8 800044F8 00000000 */ nop
/* 0050FC 800044FC 00000000 */ nop
/* 005100 80004500 00000000 */ nop
/* 005104 80004504 00000000 */ nop
/* 005108 80004508 00000000 */ nop
/* 00510C 8000450C 00000000 */ nop
/* 005110 80004510 00000000 */ nop
/* 005114 80004514 00000000 */ nop
/* 005118 80004518 00000000 */ nop
/* 00511C 8000451C 00000000 */ nop
/* 005120 80004520 00000000 */ nop
/* 005124 80004524 00000000 */ nop
/* 005128 80004528 00000000 */ nop
/* 00512C 8000452C 00000000 */ nop
/* 005130 80004530 00000000 */ nop
/* 005134 80004534 00000000 */ nop
/* 005138 80004538 00000000 */ nop
/* 00513C 8000453C 00000000 */ nop
/* 005140 80004540 00000000 */ nop
/* 005144 80004544 00000000 */ nop
/* 005148 80004548 00000000 */ nop
/* 00514C 8000454C 00000000 */ nop

View File

@ -1,57 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel func_800D71F0
/* B4E390 800D71F0 34018800 */ li $at, 34816
/* B4E394 800D71F4 0081082A */ slt $at, $a0, $at
/* B4E398 800D71F8 14200010 */ bnez $at, .L800D723C
/* B4E39C 800D71FC 240600BC */ li $a2, 188
/* B4E3A0 800D7200 00042A02 */ srl $a1, $a0, 8
/* B4E3A4 800D7204 20A5FF78 */ addi $a1, $a1, -0x88
/* B4E3A8 800D7208 00C50019 */ multu $a2, $a1
/* B4E3AC 800D720C 308700FF */ andi $a3, $a0, 0xff
/* B4E3B0 800D7210 20E7FFC0 */ addi $a3, $a3, -0x40
/* B4E3B4 800D7214 28E10040 */ slti $at, $a3, 0x40
/* B4E3B8 800D7218 00003012 */ mflo $a2
/* B4E3BC 800D721C 54200003 */ bnezl $at, .L800D722C
/* B4E3C0 800D7220 00003012 */ mflo $a2
/* B4E3C4 800D7224 20E7FFFF */ addi $a3, $a3, -1
/* B4E3C8 800D7228 00003012 */ mflo $a2
.L800D722C:
/* B4E3CC 800D722C 20E7030A */ addi $a3, $a3, 0x30a
/* B4E3D0 800D7230 00E63820 */ add $a3, $a3, $a2
/* B4E3D4 800D7234 03E00008 */ jr $ra
/* B4E3D8 800D7238 000711C0 */ sll $v0, $a3, 7
.L800D723C:
/* B4E3DC 800D723C 00042A02 */ srl $a1, $a0, 8
/* B4E3E0 800D7240 20A5FF7F */ addi $a1, $a1, -0x81
/* B4E3E4 800D7244 00C50019 */ multu $a2, $a1
/* B4E3E8 800D7248 308700FF */ andi $a3, $a0, 0xff
/* B4E3EC 800D724C 20E7FFC0 */ addi $a3, $a3, -0x40
/* B4E3F0 800D7250 28E10040 */ slti $at, $a3, 0x40
/* B4E3F4 800D7254 00003012 */ mflo $a2
/* B4E3F8 800D7258 54200003 */ bnezl $at, .L800D7268
/* B4E3FC 800D725C 00003012 */ mflo $a2
/* B4E400 800D7260 20E7FFFF */ addi $a3, $a3, -1
/* B4E404 800D7264 00003012 */ mflo $a2
.L800D7268:
/* B4E408 800D7268 00E63820 */ add $a3, $a3, $a2
/* B4E40C 800D726C 3C06800D */ lui $a2, %hi(D_800D7288) # $a2, 0x800d
/* B4E410 800D7270 00073840 */ sll $a3, $a3, 1
/* B4E414 800D7274 24C67288 */ addiu $a2, %lo(D_800D7288) # addiu $a2, $a2, 0x7288
/* B4E418 800D7278 00E63820 */ add $a3, $a3, $a2
/* B4E41C 800D727C 84E60000 */ lh $a2, ($a3)
/* B4E420 800D7280 03E00008 */ jr $ra
/* B4E424 800D7284 000611C0 */ sll $v0, $a2, 7
glabel D_800D7288
.incbin "baserom.z64", 0xB4E428, 0xB4EE70-0xB4E428

View File

@ -1,37 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.set BOOT_STACK_SIZE, 0x400
glabel entrypoint # 0x80000400
lui $t0, %hi(_bootSegmentBssStart)
addiu $t0, %lo(_bootSegmentBssStart)
li $t1, %lo(_bootSegmentBssSize)
.L8000040C:
addi $t1, $t1, -8
sw $zero, ($t0)
sw $zero, 4($t0)
bnez $t1, .L8000040C
addi $t0, $t0, 8
lui $t2, %hi(bootproc)
lui $sp, %hi(sBootThreadStack + BOOT_STACK_SIZE)
addiu $t2, %lo(bootproc)
jr $t2
addiu $sp, %lo(sBootThreadStack + BOOT_STACK_SIZE)
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop

View File

@ -1,714 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
glabel __osHwIntTable
.word 0, 0
.word 0, 0
.word 0, 0
.word 0, 0
.word 0, 0
glabel __osPiIntTable
.word 0
.word 0
.section .rodata
glabel __osIntOffTable
.byte 0x00 /* redispatch */
.byte 0x14 /* prenmi */
.byte 0x18 /* IP6_Hdlr */
.byte 0x18 /* IP6_Hdlr */
.byte 0x1c /* IP7_Hdlr */
.byte 0x1c /* IP7_Hdlr */
.byte 0x1c /* IP7_Hdlr */
.byte 0x1c /* IP7_Hdlr */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x20 /* counter */
.byte 0x00 /* redispatch */
.byte 0x04 /* sw1 */
.byte 0x08 /* sw2 */
.byte 0x08 /* sw2 */
.byte 0x0c /* rcp */
.byte 0x0c /* rcp */
.byte 0x0c /* rcp */
.byte 0x0c /* rcp */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
.byte 0x10 /* cart */
glabel __osIntTable
.word redispatch
.word sw1
.word sw2
.word rcp
.word cart
.word prenmi
.word IP6_Hdlr
.word IP7_Hdlr
.word counter
.section .text
.balign 16
glabel __osExceptionPreamble
/* 0045D0 800039D0 3C1A8000 */ lui $k0, %hi(__osException) # $k0, 0x8000
/* 0045D4 800039D4 275A39E0 */ addiu $k0, %lo(__osException) # addiu $k0, $k0, 0x39e0
/* 0045D8 800039D8 03400008 */ jr $k0
/* 0045DC 800039DC 00000000 */ nop
glabel __osException
/* 0045E0 800039E0 3C1A8001 */ lui $k0, %hi(__osThreadSave) # $k0, 0x8001
/* 0045E4 800039E4 275A5890 */ addiu $k0, %lo(__osThreadSave) # addiu $k0, $k0, 0x5890
/* 0045E8 800039E8 FF410020 */ sd $at, 0x20($k0)
/* 0045EC 800039EC 401B6000 */ mfc0 $k1, $12
/* 0045F0 800039F0 AF5B0118 */ sw $k1, 0x118($k0)
/* 0045F4 800039F4 2401FFFC */ li $at, -4
/* 0045F8 800039F8 0361D824 */ and $k1, $k1, $at
/* 0045FC 800039FC 409B6000 */ mtc0 $k1, $12
/* 004600 80003A00 FF480058 */ sd $t0, 0x58($k0)
/* 004604 80003A04 FF490060 */ sd $t1, 0x60($k0)
/* 004608 80003A08 FF4A0068 */ sd $t2, 0x68($k0)
/* 00460C 80003A0C AF400018 */ sw $zero, 0x18($k0)
/* 004610 80003A10 40086800 */ mfc0 $t0, $13
/* 004614 80003A14 03404025 */ move $t0, $k0
/* 004618 80003A18 3C1A8001 */ lui $k0, %hi(__osRunningThread) # $k0, 0x8001
/* 00461C 80003A1C 8F5AAD50 */ lw $k0, %lo(__osRunningThread)($k0)
/* 004620 80003A20 DD090020 */ ld $t1, 0x20($t0)
/* 004624 80003A24 FF490020 */ sd $t1, 0x20($k0)
/* 004628 80003A28 DD090118 */ ld $t1, 0x118($t0)
/* 00462C 80003A2C FF490118 */ sd $t1, 0x118($k0)
/* 004630 80003A30 DD090058 */ ld $t1, 0x58($t0)
/* 004634 80003A34 FF490058 */ sd $t1, 0x58($k0)
/* 004638 80003A38 DD090060 */ ld $t1, 0x60($t0)
/* 00463C 80003A3C FF490060 */ sd $t1, 0x60($k0)
/* 004640 80003A40 DD090068 */ ld $t1, 0x68($t0)
/* 004644 80003A44 FF490068 */ sd $t1, 0x68($k0)
/* 004648 80003A48 8F5B0118 */ lw $k1, 0x118($k0)
/* 00464C 80003A4C 00004012 */ mflo $t0
/* 004650 80003A50 FF480108 */ sd $t0, 0x108($k0)
/* 004654 80003A54 00004010 */ mfhi $t0
/* 004658 80003A58 3369FF00 */ andi $t1, $k1, 0xff00
/* 00465C 80003A5C FF420028 */ sd $v0, 0x28($k0)
/* 004660 80003A60 FF430030 */ sd $v1, 0x30($k0)
/* 004664 80003A64 FF440038 */ sd $a0, 0x38($k0)
/* 004668 80003A68 FF450040 */ sd $a1, 0x40($k0)
/* 00466C 80003A6C FF460048 */ sd $a2, 0x48($k0)
/* 004670 80003A70 FF470050 */ sd $a3, 0x50($k0)
/* 004674 80003A74 FF4B0070 */ sd $t3, 0x70($k0)
/* 004678 80003A78 FF4C0078 */ sd $t4, 0x78($k0)
/* 00467C 80003A7C FF4D0080 */ sd $t5, 0x80($k0)
/* 004680 80003A80 FF4E0088 */ sd $t6, 0x88($k0)
/* 004684 80003A84 FF4F0090 */ sd $t7, 0x90($k0)
/* 004688 80003A88 FF500098 */ sd $s0, 0x98($k0)
/* 00468C 80003A8C FF5100A0 */ sd $s1, 0xa0($k0)
/* 004690 80003A90 FF5200A8 */ sd $s2, 0xa8($k0)
/* 004694 80003A94 FF5300B0 */ sd $s3, 0xb0($k0)
/* 004698 80003A98 FF5400B8 */ sd $s4, 0xb8($k0)
/* 00469C 80003A9C FF5500C0 */ sd $s5, 0xc0($k0)
/* 0046A0 80003AA0 FF5600C8 */ sd $s6, 0xc8($k0)
/* 0046A4 80003AA4 FF5700D0 */ sd $s7, 0xd0($k0)
/* 0046A8 80003AA8 FF5800D8 */ sd $t8, 0xd8($k0)
/* 0046AC 80003AAC FF5900E0 */ sd $t9, 0xe0($k0)
/* 0046B0 80003AB0 FF5C00E8 */ sd $gp, 0xe8($k0)
/* 0046B4 80003AB4 FF5D00F0 */ sd $sp, 0xf0($k0)
/* 0046B8 80003AB8 FF5E00F8 */ sd $fp, 0xf8($k0)
/* 0046BC 80003ABC FF5F0100 */ sd $ra, 0x100($k0)
/* 0046C0 80003AC0 11200011 */ beqz $t1, savercp
/* 0046C4 80003AC4 FF480110 */ sd $t0, 0x110($k0)
/* 0046C8 80003AC8 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 0046CC 80003ACC 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 0046D0 80003AD0 8D080000 */ lw $t0, ($t0)
/* 0046D4 80003AD4 2401FFFF */ li $at, -1
/* 0046D8 80003AD8 01015026 */ xor $t2, $t0, $at
/* 0046DC 80003ADC 3C01FFFF */ lui $at, (0xFFFF00FF >> 16) # lui $at, 0xffff
/* 0046E0 80003AE0 314AFF00 */ andi $t2, $t2, 0xff00
/* 0046E4 80003AE4 342100FF */ ori $at, (0xFFFF00FF & 0xFFFF) # ori $at, $at, 0xff
/* 0046E8 80003AE8 012A6025 */ or $t4, $t1, $t2
/* 0046EC 80003AEC 03615824 */ and $t3, $k1, $at
/* 0046F0 80003AF0 3108FF00 */ andi $t0, $t0, 0xff00
/* 0046F4 80003AF4 016C5825 */ or $t3, $t3, $t4
/* 0046F8 80003AF8 01284824 */ and $t1, $t1, $t0
/* 0046FC 80003AFC 0361D824 */ and $k1, $k1, $at
/* 004700 80003B00 AF4B0118 */ sw $t3, 0x118($k0)
/* 004704 80003B04 0369D825 */ or $k1, $k1, $t1
savercp:
/* 004708 80003B08 3C09A430 */ lui $t1, %hi(D_A430000C) # $t1, 0xa430
/* 00470C 80003B0C 8D29000C */ lw $t1, %lo(D_A430000C)($t1)
/* 004710 80003B10 1120000B */ beqz $t1, endrcp
/* 004714 80003B14 00000000 */ nop
/* 004718 80003B18 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 00471C 80003B1C 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 004720 80003B20 8D080000 */ lw $t0, ($t0)
/* 004724 80003B24 8F4C0128 */ lw $t4, 0x128($k0)
/* 004728 80003B28 2401FFFF */ li $at, -1
/* 00472C 80003B2C 00084402 */ srl $t0, $t0, 0x10
/* 004730 80003B30 01014026 */ xor $t0, $t0, $at
/* 004734 80003B34 3108003F */ andi $t0, $t0, 0x3f
/* 004738 80003B38 010C4024 */ and $t0, $t0, $t4
/* 00473C 80003B3C 01284825 */ or $t1, $t1, $t0
endrcp:
/* 004740 80003B40 AF490128 */ sw $t1, 0x128($k0)
/* 004744 80003B44 40087000 */ mfc0 $t0, $14
/* 004748 80003B48 AF48011C */ sw $t0, 0x11c($k0)
/* 00474C 80003B4C 8F480018 */ lw $t0, 0x18($k0)
/* 004750 80003B50 11000014 */ beqz $t0, no_rdb_mesg
/* 004754 80003B54 00000000 */ nop
/* 004758 80003B58 4448F800 */ cfc1 $t0, $31
/* 00475C 80003B5C 00000000 */ nop
/* 004760 80003B60 AF48012C */ sw $t0, 0x12c($k0)
/* 004764 80003B64 F7400130 */ sdc1 $f0, 0x130($k0)
/* 004768 80003B68 F7420138 */ sdc1 $f2, 0x138($k0)
/* 00476C 80003B6C F7440140 */ sdc1 $f4, 0x140($k0)
/* 004770 80003B70 F7460148 */ sdc1 $f6, 0x148($k0)
/* 004774 80003B74 F7480150 */ sdc1 $f8, 0x150($k0)
/* 004778 80003B78 F74A0158 */ sdc1 $f10, 0x158($k0)
/* 00477C 80003B7C F74C0160 */ sdc1 $f12, 0x160($k0)
/* 004780 80003B80 F74E0168 */ sdc1 $f14, 0x168($k0)
/* 004784 80003B84 F7500170 */ sdc1 $f16, 0x170($k0)
/* 004788 80003B88 F7520178 */ sdc1 $f18, 0x178($k0)
/* 00478C 80003B8C F7540180 */ sdc1 $f20, 0x180($k0)
/* 004790 80003B90 F7560188 */ sdc1 $f22, 0x188($k0)
/* 004794 80003B94 F7580190 */ sdc1 $f24, 0x190($k0)
/* 004798 80003B98 F75A0198 */ sdc1 $f26, 0x198($k0)
/* 00479C 80003B9C F75C01A0 */ sdc1 $f28, 0x1a0($k0)
/* 0047A0 80003BA0 F75E01A8 */ sdc1 $f30, 0x1a8($k0)
no_rdb_mesg:
/* 0047A4 80003BA4 40086800 */ mfc0 $t0, $13
/* 0047A8 80003BA8 AF480120 */ sw $t0, 0x120($k0)
/* 0047AC 80003BAC 24090002 */ li $t1, 2
/* 0047B0 80003BB0 A7490010 */ sh $t1, 0x10($k0)
/* 0047B4 80003BB4 3109007C */ andi $t1, $t0, 0x7c
/* 0047B8 80003BB8 240A0024 */ li $t2, 36
/* 0047BC 80003BBC 112A00B6 */ beq $t1, $t2, handle_break
/* 0047C0 80003BC0 00000000 */ nop
/* 0047C4 80003BC4 240A002C */ li $t2, 44
/* 0047C8 80003BC8 112A0105 */ beq $t1, $t2, handle_CpU
/* 0047CC 80003BCC 00000000 */ nop
/* 0047D0 80003BD0 240A0000 */ li $t2, 0
/* 0047D4 80003BD4 152A00C9 */ bne $t1, $t2, panic
/* 0047D8 80003BD8 00000000 */ nop
/* 0047DC 80003BDC 03688024 */ and $s0, $k1, $t0
next_interrupt:
/* 0047E0 80003BE0 3209FF00 */ andi $t1, $s0, 0xff00
/* 0047E4 80003BE4 00095302 */ srl $t2, $t1, 0xc
/* 0047E8 80003BE8 15400003 */ bnez $t2, .L80003BF8
/* 0047EC 80003BEC 00000000 */ nop
/* 0047F0 80003BF0 00095202 */ srl $t2, $t1, 8
/* 0047F4 80003BF4 214A0010 */ addi $t2, $t2, 0x10
.L80003BF8:
/* 0047F8 80003BF8 3C018001 */ lui $at, %hi(__osIntOffTable)
/* 0047FC 80003BFC 002A0821 */ addu $at, $at, $t2
/* 004800 80003C00 902A20F0 */ lbu $t2, %lo(__osIntOffTable)($at)
/* 004804 80003C04 3C018001 */ lui $at, %hi(__osIntTable)
/* 004808 80003C08 002A0821 */ addu $at, $at, $t2
/* 00480C 80003C0C 8C2A2110 */ lw $t2, %lo(__osIntTable)($at)
/* 004810 80003C10 01400008 */ jr $t2
/* 004814 80003C14 00000000 */ nop
IP6_Hdlr:
/* 004818 80003C18 2401DFFF */ li $at, -8193
/* 00481C 80003C1C 1000FFF0 */ b next_interrupt
/* 004820 80003C20 02018024 */ and $s0, $s0, $at
IP7_Hdlr:
/* 004824 80003C24 2401BFFF */ li $at, -16385
/* 004828 80003C28 1000FFED */ b next_interrupt
/* 00482C 80003C2C 02018024 */ and $s0, $s0, $at
counter:
/* 004830 80003C30 40095800 */ mfc0 $t1, $11
/* 004834 80003C34 40895800 */ mtc0 $t1, $11
/* 004838 80003C38 0C000FCB */ jal send_mesg
/* 00483C 80003C3C 24040018 */ li $a0, 24
/* 004840 80003C40 3C01FFFF */ lui $at, (0xFFFF7FFF >> 16) # lui $at, 0xffff
/* 004844 80003C44 34217FFF */ ori $at, (0xFFFF7FFF & 0xFFFF) # ori $at, $at, 0x7fff
/* 004848 80003C48 1000FFE5 */ b next_interrupt
/* 00484C 80003C4C 02018024 */ and $s0, $s0, $at
cart:
/* 004850 80003C50 3C098001 */ lui $t1, %hi(__osHwIntTable) # $t1, 0x8001
/* 004854 80003C54 2529AD10 */ addiu $t1, %lo(__osHwIntTable) # addiu $t1, $t1, -0x52f0
/* 004858 80003C58 8D2A0008 */ lw $t2, 8($t1)
/* 00485C 80003C5C 2401F7FF */ li $at, -2049
/* 004860 80003C60 02018024 */ and $s0, $s0, $at
/* 004864 80003C64 11400007 */ beqz $t2, .L80003C84
/* 004868 80003C68 21290008 */ addi $t1, $t1, 8
/* 00486C 80003C6C 0140F809 */ jalr $t2
/* 004870 80003C70 8D3D0004 */ lw $sp, 4($t1)
/* 004874 80003C74 10400003 */ beqz $v0, .L80003C84
/* 004878 80003C78 00000000 */ nop
/* 00487C 80003C7C 1000008C */ b redispatch
/* 004880 80003C80 00000000 */ nop
.L80003C84:
/* 004884 80003C84 0C000FCB */ jal send_mesg
/* 004888 80003C88 24040010 */ li $a0, 16
/* 00488C 80003C8C 1000FFD4 */ b next_interrupt
/* 004890 80003C90 00000000 */ nop
rcp:
/* 004894 80003C94 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 004898 80003C98 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 00489C 80003C9C 8D080000 */ lw $t0, ($t0)
/* 0048A0 80003CA0 3C11A430 */ lui $s1, %hi(D_A4300008) # $s1, 0xa430
/* 0048A4 80003CA4 8E310008 */ lw $s1, %lo(D_A4300008)($s1)
/* 0048A8 80003CA8 00084402 */ srl $t0, $t0, 0x10
/* 0048AC 80003CAC 02288824 */ and $s1, $s1, $t0
/* 0048B0 80003CB0 32290001 */ andi $t1, $s1, 1
/* 0048B4 80003CB4 11200013 */ beqz $t1, vi
/* 0048B8 80003CB8 00000000 */ nop
/* 0048BC 80003CBC 3C0CA404 */ lui $t4, %hi(D_A4040010) # $t4, 0xa404
/* 0048C0 80003CC0 8D8C0010 */ lw $t4, %lo(D_A4040010)($t4)
/* 0048C4 80003CC4 34098008 */ li $t1, 32776
/* 0048C8 80003CC8 3C01A404 */ lui $at, %hi(D_A4040010) # $at, 0xa404
/* 0048CC 80003CCC 318C0300 */ andi $t4, $t4, 0x300
/* 0048D0 80003CD0 3231003E */ andi $s1, $s1, 0x3e
/* 0048D4 80003CD4 11800007 */ beqz $t4, sp_other_break
/* 0048D8 80003CD8 AC290010 */ sw $t1, %lo(D_A4040010)($at)
/* 0048DC 80003CDC 0C000FCB */ jal send_mesg
/* 0048E0 80003CE0 24040020 */ li $a0, 32
/* 0048E4 80003CE4 12200042 */ beqz $s1, NoMoreRcpInts
/* 0048E8 80003CE8 00000000 */ nop
/* 0048EC 80003CEC 10000005 */ b vi
/* 0048F0 80003CF0 00000000 */ nop
sp_other_break:
/* 0048F4 80003CF4 0C000FCB */ jal send_mesg
/* 0048F8 80003CF8 24040058 */ li $a0, 88
/* 0048FC 80003CFC 1220003C */ beqz $s1, NoMoreRcpInts
/* 004900 80003D00 00000000 */ nop
vi:
/* 004904 80003D04 32290008 */ andi $t1, $s1, 8
/* 004908 80003D08 11200007 */ beqz $t1, ai
/* 00490C 80003D0C 3C01A440 */ lui $at, %hi(D_A4400010) # $at, 0xa440
/* 004910 80003D10 32310037 */ andi $s1, $s1, 0x37
/* 004914 80003D14 AC200010 */ sw $zero, %lo(D_A4400010)($at)
/* 004918 80003D18 0C000FCB */ jal send_mesg
/* 00491C 80003D1C 24040038 */ li $a0, 56
/* 004920 80003D20 12200033 */ beqz $s1, NoMoreRcpInts
/* 004924 80003D24 00000000 */ nop
ai:
/* 004928 80003D28 32290004 */ andi $t1, $s1, 4
/* 00492C 80003D2C 11200009 */ beqz $t1, si
/* 004930 80003D30 00000000 */ nop
/* 004934 80003D34 24090001 */ li $t1, 1
/* 004938 80003D38 3C01A450 */ lui $at, %hi(D_A450000C) # $at, 0xa450
/* 00493C 80003D3C 3231003B */ andi $s1, $s1, 0x3b
/* 004940 80003D40 AC29000C */ sw $t1, %lo(D_A450000C)($at)
/* 004944 80003D44 0C000FCB */ jal send_mesg
/* 004948 80003D48 24040030 */ li $a0, 48
/* 00494C 80003D4C 12200028 */ beqz $s1, NoMoreRcpInts
/* 004950 80003D50 00000000 */ nop
si:
/* 004954 80003D54 32290002 */ andi $t1, $s1, 2
/* 004958 80003D58 11200007 */ beqz $t1, pi
/* 00495C 80003D5C 3C01A480 */ lui $at, %hi(D_A4800018) # $at, 0xa480
/* 004960 80003D60 3231003D */ andi $s1, $s1, 0x3d
/* 004964 80003D64 AC200018 */ sw $zero, %lo(D_A4800018)($at)
/* 004968 80003D68 0C000FCB */ jal send_mesg
/* 00496C 80003D6C 24040028 */ li $a0, 40
/* 004970 80003D70 1220001F */ beqz $s1, NoMoreRcpInts
/* 004974 80003D74 00000000 */ nop
pi:
/* 004978 80003D78 32290010 */ andi $t1, $s1, 0x10
/* 00497C 80003D7C 11200013 */ beqz $t1, dp
/* 004980 80003D80 00000000 */ nop
/* 004984 80003D84 24090002 */ li $t1, 2
/* 004988 80003D88 3C01A460 */ lui $at, %hi(D_A4600010) # $at, 0xa460
/* 00498C 80003D8C AC290010 */ sw $t1, %lo(D_A4600010)($at)
/* 004990 80003D90 3C098001 */ lui $t1, %hi(__osPiIntTable) # $t1, 0x8001
/* 004994 80003D94 2529AD38 */ addiu $t1, %lo(__osPiIntTable) # addiu $t1, $t1, -0x52c8
/* 004998 80003D98 8D2A0000 */ lw $t2, ($t1)
/* 00499C 80003D9C 3231002F */ andi $s1, $s1, 0x2f
/* 0049A0 80003DA0 11400006 */ beqz $t2, .L80003DBC
/* 0049A4 80003DA4 00000000 */ nop
/* 0049A8 80003DA8 8D3D0004 */ lw $sp, 4($t1)
/* 0049AC 80003DAC 0140F809 */ jalr $t2
/* 0049B0 80003DB0 00402025 */ move $a0, $v0
/* 0049B4 80003DB4 14400003 */ bnez $v0, .L80003DC4
/* 0049B8 80003DB8 00000000 */ nop
.L80003DBC:
/* 0049BC 80003DBC 0C000FCB */ jal send_mesg
/* 0049C0 80003DC0 24040040 */ li $a0, 64
.L80003DC4:
/* 0049C4 80003DC4 1220000A */ beqz $s1, NoMoreRcpInts
/* 0049C8 80003DC8 00000000 */ nop
dp:
/* 0049CC 80003DCC 32290020 */ andi $t1, $s1, 0x20
/* 0049D0 80003DD0 11200007 */ beqz $t1, NoMoreRcpInts
/* 0049D4 80003DD4 00000000 */ nop
/* 0049D8 80003DD8 24090800 */ li $t1, 2048
/* 0049DC 80003DDC 3C01A430 */ lui $at, 0xa430
/* 0049E0 80003DE0 3231001F */ andi $s1, $s1, 0x1f
/* 0049E4 80003DE4 AC290000 */ sw $t1, ($at)
/* 0049E8 80003DE8 0C000FCB */ jal send_mesg
/* 0049EC 80003DEC 24040048 */ li $a0, 72
NoMoreRcpInts:
/* 0049F0 80003DF0 2401FBFF */ li $at, -1025
/* 0049F4 80003DF4 1000FF7A */ b next_interrupt
/* 0049F8 80003DF8 02018024 */ and $s0, $s0, $at
prenmi:
/* 0049FC 80003DFC 8F5B0118 */ lw $k1, 0x118($k0)
/* 004A00 80003E00 2401EFFF */ li $at, -4097
/* 004A04 80003E04 3C098001 */ lui $t1, %hi(__osShutdown) # $t1, 0x8001
/* 004A08 80003E08 0361D824 */ and $k1, $k1, $at
/* 004A0C 80003E0C AF5B0118 */ sw $k1, 0x118($k0)
/* 004A10 80003E10 2529ACFC */ addiu $t1, %lo(__osShutdown) # addiu $t1, $t1, -0x5304
/* 004A14 80003E14 8D2A0000 */ lw $t2, ($t1)
/* 004A18 80003E18 11400003 */ beqz $t2, firstnmi
/* 004A1C 80003E1C 2401EFFF */ li $at, -4097
/* 004A20 80003E20 10000023 */ b redispatch
/* 004A24 80003E24 02018024 */ and $s0, $s0, $at
firstnmi:
/* 004A28 80003E28 240A0001 */ li $t2, 1
/* 004A2C 80003E2C AD2A0000 */ sw $t2, ($t1)
/* 004A30 80003E30 0C000FCB */ jal send_mesg
/* 004A34 80003E34 24040070 */ li $a0, 112
/* 004A38 80003E38 3C0A8001 */ lui $t2, %hi(__osRunQueue) # $t2, 0x8001
/* 004A3C 80003E3C 8D4AAD48 */ lw $t2, %lo(__osRunQueue)($t2)
/* 004A40 80003E40 2401EFFF */ li $at, -4097
/* 004A44 80003E44 02018024 */ and $s0, $s0, $at
/* 004A48 80003E48 8D5B0118 */ lw $k1, 0x118($t2)
/* 004A4C 80003E4C 0361D824 */ and $k1, $k1, $at
/* 004A50 80003E50 10000017 */ b redispatch
/* 004A54 80003E54 AD5B0118 */ sw $k1, 0x118($t2)
sw2:
/* 004A58 80003E58 2401FDFF */ li $at, -513
/* 004A5C 80003E5C 01014024 */ and $t0, $t0, $at
/* 004A60 80003E60 40886800 */ mtc0 $t0, $13
/* 004A64 80003E64 0C000FCB */ jal send_mesg
/* 004A68 80003E68 24040008 */ li $a0, 8
/* 004A6C 80003E6C 2401FDFF */ li $at, -513
/* 004A70 80003E70 1000FF5B */ b next_interrupt
/* 004A74 80003E74 02018024 */ and $s0, $s0, $at
sw1:
/* 004A78 80003E78 2401FEFF */ li $at, -257
/* 004A7C 80003E7C 01014024 */ and $t0, $t0, $at
/* 004A80 80003E80 40886800 */ mtc0 $t0, $13
/* 004A84 80003E84 0C000FCB */ jal send_mesg
/* 004A88 80003E88 24040000 */ li $a0, 0
/* 004A8C 80003E8C 2401FEFF */ li $at, -257
/* 004A90 80003E90 1000FF53 */ b next_interrupt
/* 004A94 80003E94 02018024 */ and $s0, $s0, $at
handle_break:
/* 004A98 80003E98 24090001 */ li $t1, 1
/* 004A9C 80003E9C A7490012 */ sh $t1, 0x12($k0)
/* 004AA0 80003EA0 0C000FCB */ jal send_mesg
/* 004AA4 80003EA4 24040050 */ li $a0, 80
/* 004AA8 80003EA8 10000001 */ b redispatch
/* 004AAC 80003EAC 00000000 */ nop
redispatch:
/* 004AB0 80003EB0 3C0A8001 */ lui $t2, %hi(__osRunQueue) # $t2, 0x8001
/* 004AB4 80003EB4 8D4AAD48 */ lw $t2, %lo(__osRunQueue)($t2)
/* 004AB8 80003EB8 8F490004 */ lw $t1, 4($k0)
/* 004ABC 80003EBC 8D4B0004 */ lw $t3, 4($t2)
/* 004AC0 80003EC0 012B082A */ slt $at, $t1, $t3
/* 004AC4 80003EC4 10200007 */ beqz $at, enqueueRunning
/* 004AC8 80003EC8 00000000 */ nop
/* 004ACC 80003ECC 3C048001 */ lui $a0, %hi(__osRunQueue) # $a0, 0x8001
/* 004AD0 80003ED0 03402825 */ move $a1, $k0
/* 004AD4 80003ED4 0C001045 */ jal __osEnqueueThread
/* 004AD8 80003ED8 2484AD48 */ addiu $a0, %lo(__osRunQueue) # addiu $a0, $a0, -0x52b8
/* 004ADC 80003EDC 0800105D */ j __osDispatchThread
/* 004AE0 80003EE0 00000000 */ nop
enqueueRunning:
/* 004AE4 80003EE4 3C098001 */ lui $t1, %hi(__osRunQueue) # $t1, 0x8001
/* 004AE8 80003EE8 2529AD48 */ addiu $t1, %lo(__osRunQueue) # addiu $t1, $t1, -0x52b8
/* 004AEC 80003EEC 8D2A0000 */ lw $t2, ($t1)
/* 004AF0 80003EF0 AF4A0000 */ sw $t2, ($k0)
/* 004AF4 80003EF4 0800105D */ j __osDispatchThread
/* 004AF8 80003EF8 AD3A0000 */ sw $k0, ($t1)
panic:
/* 004AFC 80003EFC 3C018001 */ lui $at, %hi(__osFaultedThread) # $at, 0x8001
/* 004B00 80003F00 AC3AAD54 */ sw $k0, %lo(__osFaultedThread)($at)
/* 004B04 80003F04 24090001 */ li $t1, 1
/* 004B08 80003F08 A7490010 */ sh $t1, 0x10($k0)
/* 004B0C 80003F0C 24090002 */ li $t1, 2
/* 004B10 80003F10 A7490012 */ sh $t1, 0x12($k0)
/* 004B14 80003F14 400A4000 */ mfc0 $t2, $8
/* 004B18 80003F18 AF4A0124 */ sw $t2, 0x124($k0)
/* 004B1C 80003F1C 0C000FCB */ jal send_mesg
/* 004B20 80003F20 24040060 */ li $a0, 96
/* 004B24 80003F24 0800105D */ j __osDispatchThread
/* 004B28 80003F28 00000000 */ nop
glabel send_mesg
/* 004B2C 80003F2C 3C0A8001 */ lui $t2, %hi(__osEventStateTab) # $t2, 0x8001
/* 004B30 80003F30 254A5A40 */ addiu $t2, %lo(__osEventStateTab) # addiu $t2, $t2, 0x5a40
/* 004B34 80003F34 01445021 */ addu $t2, $t2, $a0
/* 004B38 80003F38 8D490000 */ lw $t1, ($t2)
/* 004B3C 80003F3C 03E09025 */ move $s2, $ra
/* 004B40 80003F40 11200025 */ beqz $t1, send_done
/* 004B44 80003F44 00000000 */ nop
/* 004B48 80003F48 8D2B0008 */ lw $t3, 8($t1)
/* 004B4C 80003F4C 8D2C0010 */ lw $t4, 0x10($t1)
/* 004B50 80003F50 016C082A */ slt $at, $t3, $t4
/* 004B54 80003F54 10200020 */ beqz $at, send_done
/* 004B58 80003F58 00000000 */ nop
/* 004B5C 80003F5C 8D2D000C */ lw $t5, 0xc($t1)
/* 004B60 80003F60 01AB6821 */ addu $t5, $t5, $t3
/* 004B64 80003F64 01AC001A */ div $zero, $t5, $t4
/* 004B68 80003F68 15800002 */ bnez $t4, .L80003F74
/* 004B6C 80003F6C 00000000 */ nop
/* 004B70 80003F70 0007000D */ break 7
.L80003F74:
/* 004B74 80003F74 2401FFFF */ li $at, -1
/* 004B78 80003F78 15810004 */ bne $t4, $at, .L80003F8C
/* 004B7C 80003F7C 3C018000 */ lui $at, 0x8000
/* 004B80 80003F80 15A10002 */ bne $t5, $at, .L80003F8C
/* 004B84 80003F84 00000000 */ nop
/* 004B88 80003F88 0006000D */ break 6
.L80003F8C:
/* 004B8C 80003F8C 8D2C0014 */ lw $t4, 0x14($t1)
/* 004B90 80003F90 00006810 */ mfhi $t5
/* 004B94 80003F94 000D6880 */ sll $t5, $t5, 2
/* 004B98 80003F98 018D6021 */ addu $t4, $t4, $t5
/* 004B9C 80003F9C 8D4D0004 */ lw $t5, 4($t2)
/* 004BA0 80003FA0 256A0001 */ addiu $t2, $t3, 1
/* 004BA4 80003FA4 AD8D0000 */ sw $t5, ($t4)
/* 004BA8 80003FA8 AD2A0008 */ sw $t2, 8($t1)
/* 004BAC 80003FAC 8D2A0000 */ lw $t2, ($t1)
/* 004BB0 80003FB0 8D4B0000 */ lw $t3, ($t2)
/* 004BB4 80003FB4 11600008 */ beqz $t3, send_done
/* 004BB8 80003FB8 00000000 */ nop
/* 004BBC 80003FBC 0C001057 */ jal __osPopThread
/* 004BC0 80003FC0 01202025 */ move $a0, $t1
/* 004BC4 80003FC4 00405025 */ move $t2, $v0
/* 004BC8 80003FC8 3C048001 */ lui $a0, %hi(__osRunQueue) # $a0, 0x8001
/* 004BCC 80003FCC 01402825 */ move $a1, $t2
/* 004BD0 80003FD0 0C001045 */ jal __osEnqueueThread
/* 004BD4 80003FD4 2484AD48 */ addiu $a0, %lo(__osRunQueue) # addiu $a0, $a0, -0x52b8
send_done:
/* 004BD8 80003FD8 02400008 */ jr $s2
/* 004BDC 80003FDC 00000000 */ nop
handle_CpU:
/* 004BE0 80003FE0 3C013000 */ lui $at, 0x3000
/* 004BE4 80003FE4 01014824 */ and $t1, $t0, $at
/* 004BE8 80003FE8 00094F02 */ srl $t1, $t1, 0x1c
/* 004BEC 80003FEC 240A0001 */ li $t2, 1
/* 004BF0 80003FF0 152AFFC2 */ bne $t1, $t2, panic
/* 004BF4 80003FF4 00000000 */ nop
/* 004BF8 80003FF8 8F5B0118 */ lw $k1, 0x118($k0)
/* 004BFC 80003FFC 3C012000 */ lui $at, 0x2000
glabel func_80004000
/* 004C00 80004000 24090001 */ li $t1, 1
/* 004C04 80004004 0361D825 */ or $k1, $k1, $at
/* 004C08 80004008 AF490018 */ sw $t1, 0x18($k0)
/* 004C0C 8000400C 1000FFB5 */ b enqueueRunning
/* 004C10 80004010 AF5B0118 */ sw $k1, 0x118($k0)
glabel __osEnqueueAndYield
/* 004C14 80004014 3C058001 */ lui $a1, %hi(__osRunningThread) # $a1, 0x8001
/* 004C18 80004018 8CA5AD50 */ lw $a1, %lo(__osRunningThread)($a1)
/* 004C1C 8000401C 40086000 */ mfc0 $t0, $12
/* 004C20 80004020 8CBB0018 */ lw $k1, 0x18($a1)
/* 004C24 80004024 35080002 */ ori $t0, $t0, 2
/* 004C28 80004028 ACA80118 */ sw $t0, 0x118($a1)
/* 004C2C 8000402C FCB00098 */ sd $s0, 0x98($a1)
/* 004C30 80004030 FCB100A0 */ sd $s1, 0xa0($a1)
/* 004C34 80004034 FCB200A8 */ sd $s2, 0xa8($a1)
/* 004C38 80004038 FCB300B0 */ sd $s3, 0xb0($a1)
/* 004C3C 8000403C FCB400B8 */ sd $s4, 0xb8($a1)
/* 004C40 80004040 FCB500C0 */ sd $s5, 0xc0($a1)
/* 004C44 80004044 FCB600C8 */ sd $s6, 0xc8($a1)
/* 004C48 80004048 FCB700D0 */ sd $s7, 0xd0($a1)
/* 004C4C 8000404C FCBC00E8 */ sd $gp, 0xe8($a1)
/* 004C50 80004050 FCBD00F0 */ sd $sp, 0xf0($a1)
/* 004C54 80004054 FCBE00F8 */ sd $fp, 0xf8($a1)
/* 004C58 80004058 FCBF0100 */ sd $ra, 0x100($a1)
/* 004C5C 8000405C 13600009 */ beqz $k1, .L80004084
/* 004C60 80004060 ACBF011C */ sw $ra, 0x11c($a1)
/* 004C64 80004064 445BF800 */ cfc1 $k1, $31
/* 004C68 80004068 F4B40180 */ sdc1 $f20, 0x180($a1)
/* 004C6C 8000406C F4B60188 */ sdc1 $f22, 0x188($a1)
/* 004C70 80004070 F4B80190 */ sdc1 $f24, 0x190($a1)
/* 004C74 80004074 F4BA0198 */ sdc1 $f26, 0x198($a1)
/* 004C78 80004078 F4BC01A0 */ sdc1 $f28, 0x1a0($a1)
/* 004C7C 8000407C F4BE01A8 */ sdc1 $f30, 0x1a8($a1)
/* 004C80 80004080 ACBB012C */ sw $k1, 0x12c($a1)
.L80004084:
/* 004C84 80004084 8CBB0118 */ lw $k1, 0x118($a1)
/* 004C88 80004088 3369FF00 */ andi $t1, $k1, 0xff00
/* 004C8C 8000408C 1120000D */ beqz $t1, .L800040C4
/* 004C90 80004090 00000000 */ nop
/* 004C94 80004094 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 004C98 80004098 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 004C9C 8000409C 8D080000 */ lw $t0, ($t0)
/* 004CA0 800040A0 2401FFFF */ li $at, -1
/* 004CA4 800040A4 01014026 */ xor $t0, $t0, $at
/* 004CA8 800040A8 3C01FFFF */ lui $at, (0xFFFF00FF >> 16) # lui $at, 0xffff
/* 004CAC 800040AC 3108FF00 */ andi $t0, $t0, 0xff00
/* 004CB0 800040B0 342100FF */ ori $at, (0xFFFF00FF & 0xFFFF) # ori $at, $at, 0xff
/* 004CB4 800040B4 01284825 */ or $t1, $t1, $t0
/* 004CB8 800040B8 0361D824 */ and $k1, $k1, $at
/* 004CBC 800040BC 0369D825 */ or $k1, $k1, $t1
/* 004CC0 800040C0 ACBB0118 */ sw $k1, 0x118($a1)
.L800040C4:
/* 004CC4 800040C4 3C1BA430 */ lui $k1, %hi(D_A430000C) # $k1, 0xa430
/* 004CC8 800040C8 8F7B000C */ lw $k1, %lo(D_A430000C)($k1)
/* 004CCC 800040CC 1360000B */ beqz $k1, .L800040FC
/* 004CD0 800040D0 00000000 */ nop
/* 004CD4 800040D4 3C1A8001 */ lui $k0, %hi(__OSGlobalIntMask) # $k0, 0x8001
/* 004CD8 800040D8 275AAD00 */ addiu $k0, %lo(__OSGlobalIntMask) # addiu $k0, $k0, -0x5300
/* 004CDC 800040DC 8F5A0000 */ lw $k0, ($k0)
/* 004CE0 800040E0 8CA80128 */ lw $t0, 0x128($a1)
/* 004CE4 800040E4 2401FFFF */ li $at, -1
/* 004CE8 800040E8 001AD402 */ srl $k0, $k0, 0x10
/* 004CEC 800040EC 0341D026 */ xor $k0, $k0, $at
/* 004CF0 800040F0 335A003F */ andi $k0, $k0, 0x3f
/* 004CF4 800040F4 0348D024 */ and $k0, $k0, $t0
/* 004CF8 800040F8 037AD825 */ or $k1, $k1, $k0
.L800040FC:
/* 004CFC 800040FC 10800003 */ beqz $a0, .L8000410C
/* 004D00 80004100 ACBB0128 */ sw $k1, 0x128($a1)
/* 004D04 80004104 0C001045 */ jal __osEnqueueThread
/* 004D08 80004108 00000000 */ nop
.L8000410C:
/* 004D0C 8000410C 0800105D */ j __osDispatchThread
/* 004D10 80004110 00000000 */ nop
glabel __osEnqueueThread
/* 004D14 80004114 8C980000 */ lw $t8, ($a0)
/* 004D18 80004118 8CAF0004 */ lw $t7, 4($a1)
/* 004D1C 8000411C 0080C825 */ move $t9, $a0
/* 004D20 80004120 8F0E0004 */ lw $t6, 4($t8)
/* 004D24 80004124 01CF082A */ slt $at, $t6, $t7
/* 004D28 80004128 14200007 */ bnez $at, .L80004148
/* 004D2C 8000412C 00000000 */ nop
.L80004130:
/* 004D30 80004130 0300C825 */ move $t9, $t8
/* 004D34 80004134 8F180000 */ lw $t8, ($t8)
/* 004D38 80004138 8F0E0004 */ lw $t6, 4($t8)
/* 004D3C 8000413C 01CF082A */ slt $at, $t6, $t7
/* 004D40 80004140 1020FFFB */ beqz $at, .L80004130
/* 004D44 80004144 00000000 */ nop
.L80004148:
/* 004D48 80004148 8F380000 */ lw $t8, ($t9)
/* 004D4C 8000414C ACB80000 */ sw $t8, ($a1)
/* 004D50 80004150 AF250000 */ sw $a1, ($t9)
/* 004D54 80004154 03E00008 */ jr $ra
/* 004D58 80004158 ACA40008 */ sw $a0, 8($a1)
glabel __osPopThread
/* 004D5C 8000415C 8C820000 */ lw $v0, ($a0)
/* 004D60 80004160 8C590000 */ lw $t9, ($v0)
/* 004D64 80004164 03E00008 */ jr $ra
/* 004D68 80004168 AC990000 */ sw $t9, ($a0)
glabel __osNop
/* 004D6C 8000416C 03E00008 */ jr $ra
/* 004D70 80004170 00000000 */ nop
glabel __osDispatchThread
/* 004D74 80004174 3C048001 */ lui $a0, %hi(__osRunQueue) # $a0, 0x8001
/* 004D78 80004178 0C001057 */ jal __osPopThread
/* 004D7C 8000417C 2484AD48 */ addiu $a0, %lo(__osRunQueue) # addiu $a0, $a0, -0x52b8
/* 004D80 80004180 3C018001 */ lui $at, %hi(__osRunningThread) # $at, 0x8001
/* 004D84 80004184 AC22AD50 */ sw $v0, %lo(__osRunningThread)($at)
/* 004D88 80004188 24080004 */ li $t0, 4
/* 004D8C 8000418C A4480010 */ sh $t0, 0x10($v0)
/* 004D90 80004190 0040D025 */ move $k0, $v0
/* 004D94 80004194 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 004D98 80004198 8F5B0118 */ lw $k1, 0x118($k0)
/* 004D9C 8000419C 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 004DA0 800041A0 8D080000 */ lw $t0, ($t0)
/* 004DA4 800041A4 3C01FFFF */ lui $at, (0xFFFF00FF >> 16) # lui $at, 0xffff
/* 004DA8 800041A8 3369FF00 */ andi $t1, $k1, 0xff00
/* 004DAC 800041AC 342100FF */ ori $at, (0xFFFF00FF & 0xFFFF) # ori $at, $at, 0xff
/* 004DB0 800041B0 3108FF00 */ andi $t0, $t0, 0xff00
/* 004DB4 800041B4 01284824 */ and $t1, $t1, $t0
/* 004DB8 800041B8 0361D824 */ and $k1, $k1, $at
/* 004DBC 800041BC 0369D825 */ or $k1, $k1, $t1
/* 004DC0 800041C0 409B6000 */ mtc0 $k1, $12
/* 004DC4 800041C4 DF5B0108 */ ld $k1, 0x108($k0)
/* 004DC8 800041C8 DF410020 */ ld $at, 0x20($k0)
/* 004DCC 800041CC DF420028 */ ld $v0, 0x28($k0)
/* 004DD0 800041D0 03600013 */ mtlo $k1
/* 004DD4 800041D4 DF5B0110 */ ld $k1, 0x110($k0)
/* 004DD8 800041D8 DF430030 */ ld $v1, 0x30($k0)
/* 004DDC 800041DC DF440038 */ ld $a0, 0x38($k0)
/* 004DE0 800041E0 DF450040 */ ld $a1, 0x40($k0)
/* 004DE4 800041E4 DF460048 */ ld $a2, 0x48($k0)
/* 004DE8 800041E8 DF470050 */ ld $a3, 0x50($k0)
/* 004DEC 800041EC DF480058 */ ld $t0, 0x58($k0)
/* 004DF0 800041F0 DF490060 */ ld $t1, 0x60($k0)
/* 004DF4 800041F4 DF4A0068 */ ld $t2, 0x68($k0)
/* 004DF8 800041F8 DF4B0070 */ ld $t3, 0x70($k0)
/* 004DFC 800041FC DF4C0078 */ ld $t4, 0x78($k0)
/* 004E00 80004200 DF4D0080 */ ld $t5, 0x80($k0)
/* 004E04 80004204 DF4E0088 */ ld $t6, 0x88($k0)
/* 004E08 80004208 DF4F0090 */ ld $t7, 0x90($k0)
/* 004E0C 8000420C DF500098 */ ld $s0, 0x98($k0)
/* 004E10 80004210 DF5100A0 */ ld $s1, 0xa0($k0)
/* 004E14 80004214 DF5200A8 */ ld $s2, 0xa8($k0)
/* 004E18 80004218 DF5300B0 */ ld $s3, 0xb0($k0)
/* 004E1C 8000421C DF5400B8 */ ld $s4, 0xb8($k0)
/* 004E20 80004220 DF5500C0 */ ld $s5, 0xc0($k0)
/* 004E24 80004224 DF5600C8 */ ld $s6, 0xc8($k0)
/* 004E28 80004228 DF5700D0 */ ld $s7, 0xd0($k0)
/* 004E2C 8000422C DF5800D8 */ ld $t8, 0xd8($k0)
/* 004E30 80004230 DF5900E0 */ ld $t9, 0xe0($k0)
/* 004E34 80004234 DF5C00E8 */ ld $gp, 0xe8($k0)
/* 004E38 80004238 03600011 */ mthi $k1
/* 004E3C 8000423C DF5D00F0 */ ld $sp, 0xf0($k0)
/* 004E40 80004240 DF5E00F8 */ ld $fp, 0xf8($k0)
/* 004E44 80004244 DF5F0100 */ ld $ra, 0x100($k0)
/* 004E48 80004248 8F5B011C */ lw $k1, 0x11c($k0)
/* 004E4C 8000424C 409B7000 */ mtc0 $k1, $14
/* 004E50 80004250 8F5B0018 */ lw $k1, 0x18($k0)
/* 004E54 80004254 13600013 */ beqz $k1, .L800042A4
/* 004E58 80004258 00000000 */ nop
/* 004E5C 8000425C 8F5B012C */ lw $k1, 0x12c($k0)
/* 004E60 80004260 44DBF800 */ ctc1 $k1, $31
/* 004E64 80004264 D7400130 */ ldc1 $f0, 0x130($k0)
/* 004E68 80004268 D7420138 */ ldc1 $f2, 0x138($k0)
/* 004E6C 8000426C D7440140 */ ldc1 $f4, 0x140($k0)
/* 004E70 80004270 D7460148 */ ldc1 $f6, 0x148($k0)
/* 004E74 80004274 D7480150 */ ldc1 $f8, 0x150($k0)
/* 004E78 80004278 D74A0158 */ ldc1 $f10, 0x158($k0)
/* 004E7C 8000427C D74C0160 */ ldc1 $f12, 0x160($k0)
/* 004E80 80004280 D74E0168 */ ldc1 $f14, 0x168($k0)
/* 004E84 80004284 D7500170 */ ldc1 $f16, 0x170($k0)
/* 004E88 80004288 D7520178 */ ldc1 $f18, 0x178($k0)
/* 004E8C 8000428C D7540180 */ ldc1 $f20, 0x180($k0)
/* 004E90 80004290 D7560188 */ ldc1 $f22, 0x188($k0)
/* 004E94 80004294 D7580190 */ ldc1 $f24, 0x190($k0)
/* 004E98 80004298 D75A0198 */ ldc1 $f26, 0x198($k0)
/* 004E9C 8000429C D75C01A0 */ ldc1 $f28, 0x1a0($k0)
/* 004EA0 800042A0 D75E01A8 */ ldc1 $f30, 0x1a8($k0)
.L800042A4:
/* 004EA4 800042A4 8F5B0128 */ lw $k1, 0x128($k0)
/* 004EA8 800042A8 3C1A8001 */ lui $k0, %hi(__OSGlobalIntMask) # $k0, 0x8001
/* 004EAC 800042AC 275AAD00 */ addiu $k0, %lo(__OSGlobalIntMask) # addiu $k0, $k0, -0x5300
/* 004EB0 800042B0 8F5A0000 */ lw $k0, ($k0)
/* 004EB4 800042B4 001AD402 */ srl $k0, $k0, 0x10
/* 004EB8 800042B8 037AD824 */ and $k1, $k1, $k0
/* 004EBC 800042BC 001BD840 */ sll $k1, $k1, 1
/* 004EC0 800042C0 3C1A8001 */ lui $k0, %hi(__osRcpImTable) # $k0, 0x8001
/* 004EC4 800042C4 275A2160 */ addiu $k0, %lo(__osRcpImTable) # addiu $k0, $k0, 0x2160
/* 004EC8 800042C8 037AD821 */ addu $k1, $k1, $k0
/* 004ECC 800042CC 977B0000 */ lhu $k1, ($k1)
/* 004ED0 800042D0 3C1AA430 */ lui $k0, %hi(D_A430000C) # $k0, 0xa430
/* 004ED4 800042D4 275A000C */ addiu $k0, %lo(D_A430000C) # addiu $k0, $k0, 0xc
/* 004ED8 800042D8 AF5B0000 */ sw $k1, ($k0)
/* 004EDC 800042DC 00000000 */ nop
/* 004EE0 800042E0 00000000 */ nop
/* 004EE4 800042E4 00000000 */ nop
/* 004EE8 800042E8 00000000 */ nop
/* 004EEC 800042EC 42000018 */ eret
glabel __osCleanupThread
/* 004EF0 800042F0 0C0010D0 */ jal osDestroyThread
/* 004EF4 800042F4 00002025 */ move $a0, $zero

138
asm/fp.s
View File

@ -1,138 +0,0 @@
.include "macro.inc"
.section .data
glabel qNaN0x3FFFFF
.word 0x7FBFFFFF
glabel qNaN0x10000
.word 0x7F810000
glabel sNaN0x3FFFFF
.word 0x7FFFFFFF
.section .text
glabel floorf
floor.w.s $f12, $f12
cvt.s.w $f0, $f12
jr $ra
glabel floor
floor.w.d $f12, $f12
cvt.d.w $f0, $f12
jr $ra
glabel lfloorf
floor.w.s $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel lfloor
floor.w.d $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel ceilf
ceil.w.s $f12, $f12
cvt.s.w $f0, $f12
jr $ra
glabel ceil
ceil.w.d $f12, $f12
cvt.d.w $f0, $f12
jr $ra
glabel lceilf
ceil.w.s $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel lceil
ceil.w.d $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel truncf
trunc.w.s $f12, $f12
cvt.s.w $f0, $f12
jr $ra
glabel trunc
trunc.w.d $f12, $f12
cvt.d.w $f0, $f12
jr $ra
glabel ltruncf
trunc.w.s $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel ltrunc
trunc.w.d $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel nearbyintf
round.w.s $f12, $f12
cvt.s.w $f0, $f12
jr $ra
glabel nearbyint
round.w.d $f12, $f12
cvt.d.w $f0, $f12
jr $ra
glabel lnearbyintf
round.w.s $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel lnearbyint
round.w.d $f4, $f12
mfc1 $v0, $f4
nop
jr $ra
glabel roundf
li.s $f4, 0.5
nop
add.s $f0, $f12, $f4
floor.w.s $f0, $f0
cvt.s.w $f0, $f0
jr $ra
glabel round
li.d $f4, 0.5
nop
add.d $f0, $f12, $f4
floor.w.d $f0, $f0
cvt.d.w $f0, $f0
jr $ra
glabel lroundf
li.s $f4, 0.5
nop
add.s $f0, $f12, $f4
floor.w.s $f0, $f0
mfc1 $v0, $f0
nop
jr $ra
glabel lround
li.d $f4, 0.5
nop
add.d $f0, $f12, $f4
floor.w.d $f0, $f0
mfc1 $v0, $f0
nop
jr $ra

View File

@ -1,42 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
/* B7D670 801064D0 00000000 */ nop
/* B7D674 801064D4 00000000 */ nop
/* B7D678 801064D8 00000000 */ nop
/* B7D67C 801064DC 00000000 */ nop
glabel guMtxF2L
/* B7D680 801064E0 3C014780 */ li $at, 0x47800000 # 0.000000
/* B7D684 801064E4 44810000 */ mtc1 $at, $f0
/* B7D688 801064E8 3C19FFFF */ lui $t9, 0xffff
/* B7D68C 801064EC 24B80020 */ addiu $t8, $a1, 0x20
.L801064F0:
/* B7D690 801064F0 C4840000 */ lwc1 $f4, ($a0)
/* B7D694 801064F4 C48A0004 */ lwc1 $f10, 4($a0)
/* B7D698 801064F8 24A50004 */ addiu $a1, $a1, 4
/* B7D69C 801064FC 46002182 */ mul.s $f6, $f4, $f0
/* B7D6A0 80106500 24840008 */ addiu $a0, $a0, 8
/* B7D6A4 80106504 46005402 */ mul.s $f16, $f10, $f0
/* B7D6A8 80106508 4600320D */ trunc.w.s $f8, $f6
/* B7D6AC 8010650C 4600848D */ trunc.w.s $f18, $f16
/* B7D6B0 80106510 44084000 */ mfc1 $t0, $f8
/* B7D6B4 80106514 44099000 */ mfc1 $t1, $f18
/* B7D6B8 80106518 01195024 */ and $t2, $t0, $t9
/* B7D6BC 8010651C 00086C00 */ sll $t5, $t0, 0x10
/* B7D6C0 80106520 00095C02 */ srl $t3, $t1, 0x10
/* B7D6C4 80106524 312EFFFF */ andi $t6, $t1, 0xffff
/* B7D6C8 80106528 014B6025 */ or $t4, $t2, $t3
/* B7D6CC 8010652C 01AE7825 */ or $t7, $t5, $t6
/* B7D6D0 80106530 ACACFFFC */ sw $t4, -4($a1)
/* B7D6D4 80106534 14B8FFEE */ bne $a1, $t8, .L801064F0
/* B7D6D8 80106538 ACAF001C */ sw $t7, 0x1c($a1)
/* B7D6DC 8010653C 03E00008 */ jr $ra
/* B7D6E0 80106540 00000000 */ nop

View File

@ -1,31 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel guMtxIdent
/* B7AD00 80103B60 20080001 */ addi $t0, $zero, 1
/* B7AD04 80103B64 00084C00 */ sll $t1, $t0, 0x10
/* B7AD08 80103B68 AC890000 */ sw $t1, ($a0)
/* B7AD0C 80103B6C AC800004 */ sw $zero, 4($a0)
/* B7AD10 80103B70 AC880008 */ sw $t0, 8($a0)
/* B7AD14 80103B74 AC80000C */ sw $zero, 0xc($a0)
/* B7AD18 80103B78 AC800010 */ sw $zero, 0x10($a0)
/* B7AD1C 80103B7C AC890014 */ sw $t1, 0x14($a0)
/* B7AD20 80103B80 AC800018 */ sw $zero, 0x18($a0)
/* B7AD24 80103B84 AC88001C */ sw $t0, 0x1c($a0)
/* B7AD28 80103B88 AC800020 */ sw $zero, 0x20($a0)
/* B7AD2C 80103B8C AC800024 */ sw $zero, 0x24($a0)
/* B7AD30 80103B90 AC800028 */ sw $zero, 0x28($a0)
/* B7AD34 80103B94 AC80002C */ sw $zero, 0x2c($a0)
/* B7AD38 80103B98 AC800030 */ sw $zero, 0x30($a0)
/* B7AD3C 80103B9C AC800034 */ sw $zero, 0x34($a0)
/* B7AD40 80103BA0 AC800038 */ sw $zero, 0x38($a0)
/* B7AD44 80103BA4 03E00008 */ jr $ra
/* B7AD48 80103BA8 AC80003C */ sw $zero, 0x3c($a0)

View File

@ -1,32 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
## Handwritten ASM
glabel guMtxIdentF
/* B78CE0 80101B40 3C083F80 */ lui $t0, 0x3f80
/* B78CE4 80101B44 AC880000 */ sw $t0, ($a0)
/* B78CE8 80101B48 AC800004 */ sw $zero, 4($a0)
/* B78CEC 80101B4C AC800008 */ sw $zero, 8($a0)
/* B78CF0 80101B50 AC80000C */ sw $zero, 0xc($a0)
/* B78CF4 80101B54 AC800010 */ sw $zero, 0x10($a0)
/* B78CF8 80101B58 AC880014 */ sw $t0, 0x14($a0)
/* B78CFC 80101B5C AC800018 */ sw $zero, 0x18($a0)
/* B78D00 80101B60 AC80001C */ sw $zero, 0x1c($a0)
/* B78D04 80101B64 AC800020 */ sw $zero, 0x20($a0)
/* B78D08 80101B68 AC800024 */ sw $zero, 0x24($a0)
/* B78D0C 80101B6C AC880028 */ sw $t0, 0x28($a0)
/* B78D10 80101B70 AC80002C */ sw $zero, 0x2c($a0)
/* B78D14 80101B74 AC800030 */ sw $zero, 0x30($a0)
/* B78D18 80101B78 AC800034 */ sw $zero, 0x34($a0)
/* B78D1C 80101B7C AC800038 */ sw $zero, 0x38($a0)
/* B78D20 80101B80 03E00008 */ jr $ra
/* B78D24 80101B84 AC88003C */ sw $t0, 0x3c($a0)

View File

@ -1,39 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel guMtxL2F
/* B7A140 80102FA0 3C013780 */ li $at, 0x37800000 # 0.000000
/* B7A144 80102FA4 44810000 */ mtc1 $at, $f0
/* B7A148 80102FA8 3C19FFFF */ li $t9, 0xFFFF0000 # 0.000000
/* B7A14C 80102FAC 24B80020 */ addiu $t8, $a1, 0x20
.L80102FB0:
/* B7A150 80102FB0 8CA80000 */ lw $t0, ($a1)
/* B7A154 80102FB4 8CA90020 */ lw $t1, 0x20($a1)
/* B7A158 80102FB8 24A50004 */ addiu $a1, $a1, 4
/* B7A15C 80102FBC 01195024 */ and $t2, $t0, $t9
/* B7A160 80102FC0 00095C02 */ srl $t3, $t1, 0x10
/* B7A164 80102FC4 014B6025 */ or $t4, $t2, $t3
/* B7A168 80102FC8 448C2000 */ mtc1 $t4, $f4
/* B7A16C 80102FCC 00086C00 */ sll $t5, $t0, 0x10
/* B7A170 80102FD0 312EFFFF */ andi $t6, $t1, 0xffff
/* B7A174 80102FD4 01AE7825 */ or $t7, $t5, $t6
/* B7A178 80102FD8 468021A0 */ cvt.s.w $f6, $f4
/* B7A17C 80102FDC 448F5000 */ mtc1 $t7, $f10
/* B7A180 80102FE0 24840008 */ addiu $a0, $a0, 8
/* B7A184 80102FE4 46805420 */ cvt.s.w $f16, $f10
/* B7A188 80102FE8 46003202 */ mul.s $f8, $f6, $f0
/* B7A18C 80102FEC 00000000 */ nop
/* B7A190 80102FF0 46008482 */ mul.s $f18, $f16, $f0
/* B7A194 80102FF4 E488FFF8 */ swc1 $f8, -8($a0)
/* B7A198 80102FF8 14B8FFED */ bne $a1, $t8, .L80102FB0
/* B7A19C 80102FFC E492FFFC */ swc1 $f18, -4($a0)
/* B7A1A0 80103000 03E00008 */ jr $ra
/* B7A1A4 80103004 00000000 */ nop

View File

@ -1,37 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
/* B7B2F0 80104150 00000000 */ nop
/* B7B2F4 80104154 00000000 */ nop
/* B7B2F8 80104158 00000000 */ nop
/* B7B2FC 8010415C 00000000 */ nop
glabel guNormalize
/* B7B300 80104160 C4840000 */ lwc1 $f4, ($a0)
/* B7B304 80104164 C4A60000 */ lwc1 $f6, ($a1)
/* B7B308 80104168 C4C80000 */ lwc1 $f8, ($a2)
/* B7B30C 8010416C 46042282 */ mul.s $f10, $f4, $f4
/* B7B310 80104170 3C083F80 */ li $t0, 0x3F800000 # 0.000000
/* B7B314 80104174 46063402 */ mul.s $f16, $f6, $f6
/* B7B318 80104178 46105480 */ add.s $f18, $f10, $f16
/* B7B31C 8010417C 46084402 */ mul.s $f16, $f8, $f8
/* B7B320 80104180 46128280 */ add.s $f10, $f16, $f18
/* B7B324 80104184 44889000 */ mtc1 $t0, $f18
/* B7B328 80104188 46005404 */ sqrt.s $f16, $f10
/* B7B32C 8010418C 46109283 */ div.s $f10, $f18, $f16
/* B7B330 80104190 460A2402 */ mul.s $f16, $f4, $f10
/* B7B334 80104194 00000000 */ nop
/* B7B338 80104198 460A3482 */ mul.s $f18, $f6, $f10
/* B7B33C 8010419C 00000000 */ nop
/* B7B340 801041A0 460A4102 */ mul.s $f4, $f8, $f10
/* B7B344 801041A4 E4900000 */ swc1 $f16, ($a0)
/* B7B348 801041A8 E4B20000 */ swc1 $f18, ($a1)
/* B7B34C 801041AC 03E00008 */ jr $ra
/* B7B350 801041B0 E4C40000 */ swc1 $f4, ($a2)

View File

@ -1,53 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel guScale
/* B77380 801001E0 3C014780 */ li $at, 0x47800000 # 0.000000
/* B77384 801001E4 44812000 */ mtc1 $at, $f4
/* B77388 801001E8 44853000 */ mtc1 $a1, $f6
/* B7738C 801001EC AC800004 */ sw $zero, 4($a0)
/* B77390 801001F0 AC80000C */ sw $zero, 0xc($a0)
/* B77394 801001F4 46043202 */ mul.s $f8, $f6, $f4
/* B77398 801001F8 44863000 */ mtc1 $a2, $f6
/* B7739C 801001FC AC800010 */ sw $zero, 0x10($a0)
/* B773A0 80100200 AC800018 */ sw $zero, 0x18($a0)
/* B773A4 80100204 AC800024 */ sw $zero, 0x24($a0)
/* B773A8 80100208 AC80002C */ sw $zero, 0x2c($a0)
/* B773AC 8010020C AC800030 */ sw $zero, 0x30($a0)
/* B773B0 80100210 4600428D */ trunc.w.s $f10, $f8
/* B773B4 80100214 46043202 */ mul.s $f8, $f6, $f4
/* B773B8 80100218 44873000 */ mtc1 $a3, $f6
/* B773BC 8010021C AC800038 */ sw $zero, 0x38($a0)
/* B773C0 80100220 44095000 */ mfc1 $t1, $f10
/* B773C4 80100224 AC80003C */ sw $zero, 0x3c($a0)
/* B773C8 80100228 00095402 */ srl $t2, $t1, 0x10
/* B773CC 8010022C 4600428D */ trunc.w.s $f10, $f8
/* B773D0 80100230 46043202 */ mul.s $f8, $f6, $f4
/* B773D4 80100234 000A4400 */ sll $t0, $t2, 0x10
/* B773D8 80100238 00095400 */ sll $t2, $t1, 0x10
/* B773DC 8010023C 44095000 */ mfc1 $t1, $f10
/* B773E0 80100240 AC880000 */ sw $t0, ($a0)
/* B773E4 80100244 AC8A0020 */ sw $t2, 0x20($a0)
/* B773E8 80100248 00094402 */ srl $t0, $t1, 0x10
/* B773EC 8010024C 4600428D */ trunc.w.s $f10, $f8
/* B773F0 80100250 312AFFFF */ andi $t2, $t1, 0xffff
/* B773F4 80100254 AC8A0028 */ sw $t2, 0x28($a0)
/* B773F8 80100258 AC880008 */ sw $t0, 8($a0)
/* B773FC 8010025C 44095000 */ mfc1 $t1, $f10
/* B77400 80100260 00000000 */ nop
/* B77404 80100264 00095402 */ srl $t2, $t1, 0x10
/* B77408 80100268 000A4400 */ sll $t0, $t2, 0x10
/* B7740C 8010026C AC880014 */ sw $t0, 0x14($a0)
/* B77410 80100270 24080001 */ li $t0, 1
/* B77414 80100274 00095400 */ sll $t2, $t1, 0x10
/* B77418 80100278 AC8A0034 */ sw $t2, 0x34($a0)
/* B7741C 8010027C 03E00008 */ jr $ra
/* B77420 80100280 AC88001C */ sw $t0, 0x1c($a0)

View File

@ -1,66 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
/* B7CDB0 80105C10 00000000 */ nop
/* B7CDB4 80105C14 00000000 */ nop
/* B7CDB8 80105C18 00000000 */ nop
/* B7CDBC 80105C1C 00000000 */ nop
glabel guTranslate
/* B7CDC0 80105C20 3C014780 */ li $at, 0x47800000 # 0.000000
/* B7CDC4 80105C24 44812000 */ mtc1 $at, $f4
/* B7CDC8 80105C28 44853000 */ mtc1 $a1, $f6
/* B7CDCC 80105C2C AC800000 */ sw $zero, ($a0)
/* B7CDD0 80105C30 AC800014 */ sw $zero, 0x14($a0)
/* B7CDD4 80105C34 46043202 */ mul.s $f8, $f6, $f4
/* B7CDD8 80105C38 44863000 */ mtc1 $a2, $f6
/* B7CDDC 80105C3C AC800008 */ sw $zero, 8($a0)
/* B7CDE0 80105C40 AC800004 */ sw $zero, 4($a0)
/* B7CDE4 80105C44 AC80000C */ sw $zero, 0xc($a0)
/* B7CDE8 80105C48 AC800010 */ sw $zero, 0x10($a0)
/* B7CDEC 80105C4C AC800020 */ sw $zero, 0x20($a0)
/* B7CDF0 80105C50 4600428D */ trunc.w.s $f10, $f8
/* B7CDF4 80105C54 46043202 */ mul.s $f8, $f6, $f4
/* B7CDF8 80105C58 44873000 */ mtc1 $a3, $f6
/* B7CDFC 80105C5C AC800024 */ sw $zero, 0x24($a0)
/* B7CE00 80105C60 44095000 */ mfc1 $t1, $f10
/* B7CE04 80105C64 AC800028 */ sw $zero, 0x28($a0)
/* B7CE08 80105C68 AC80002C */ sw $zero, 0x2c($a0)
/* B7CE0C 80105C6C 00095402 */ srl $t2, $t1, 0x10
/* B7CE10 80105C70 4600428D */ trunc.w.s $f10, $f8
/* B7CE14 80105C74 46043202 */ mul.s $f8, $f6, $f4
/* B7CE18 80105C78 000A4400 */ sll $t0, $t2, 0x10
/* B7CE1C 80105C7C AC800030 */ sw $zero, 0x30($a0)
/* B7CE20 80105C80 440B5000 */ mfc1 $t3, $f10
/* B7CE24 80105C84 AC800034 */ sw $zero, 0x34($a0)
/* B7CE28 80105C88 000B5402 */ srl $t2, $t3, 0x10
/* B7CE2C 80105C8C 4600428D */ trunc.w.s $f10, $f8
/* B7CE30 80105C90 010A4025 */ or $t0, $t0, $t2
/* B7CE34 80105C94 AC880018 */ sw $t0, 0x18($a0)
/* B7CE38 80105C98 00094400 */ sll $t0, $t1, 0x10
/* B7CE3C 80105C9C 000B5400 */ sll $t2, $t3, 0x10
/* B7CE40 80105CA0 44095000 */ mfc1 $t1, $f10
/* B7CE44 80105CA4 000A5402 */ srl $t2, $t2, 0x10
/* B7CE48 80105CA8 010A4025 */ or $t0, $t0, $t2
/* B7CE4C 80105CAC AC880038 */ sw $t0, 0x38($a0)
/* B7CE50 80105CB0 00095402 */ srl $t2, $t1, 0x10
/* B7CE54 80105CB4 000A4400 */ sll $t0, $t2, 0x10
/* B7CE58 80105CB8 25080001 */ addiu $t0, $t0, 1
/* B7CE5C 80105CBC AC88001C */ sw $t0, 0x1c($a0)
/* B7CE60 80105CC0 3C080001 */ lui $t0, 1
/* B7CE64 80105CC4 35080000 */ ori $t0, $t0, 0
/* B7CE68 80105CC8 AC880000 */ sw $t0, ($a0)
/* B7CE6C 80105CCC AC880014 */ sw $t0, 0x14($a0)
/* B7CE70 80105CD0 3C080000 */ lui $t0, (0x00000001 >> 16) # lui $t0, 0
/* B7CE74 80105CD4 35080001 */ ori $t0, (0x00000001 & 0xFFFF) # ori $t0, $t0, 1
/* B7CE78 80105CD8 00095400 */ sll $t2, $t1, 0x10
/* B7CE7C 80105CDC AC8A003C */ sw $t2, 0x3c($a0)
/* B7CE80 80105CE0 03E00008 */ jr $ra
/* B7CE84 80105CE4 AC880008 */ sw $t0, 8($a0)

View File

@ -1,10 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.incbin "baserom.z64", 0x40, 0xFC0

View File

@ -1,13 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .rodata
.balign 16
glabel __libm_qnan_f
.word 0x7F810000

View File

@ -1,62 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel Mio0_Decompress
/* 0031B0 800025B0 8C870008 */ lw $a3, 8($a0)
/* 0031B4 800025B4 8C99000C */ lw $t9, 0xc($a0)
/* 0031B8 800025B8 8C980004 */ lw $t8, 4($a0)
/* 0031BC 800025BC 00E43820 */ add $a3, $a3, $a0
/* 0031C0 800025C0 0324C820 */ add $t9, $t9, $a0
/* 0031C4 800025C4 00003025 */ move $a2, $zero
/* 0031C8 800025C8 20840010 */ addi $a0, $a0, 0x10
/* 0031CC 800025CC 0305C020 */ add $t8, $t8, $a1
.L800025D0:
/* 0031D0 800025D0 14C00004 */ bnez $a2, .L800025E4
/* 0031D4 800025D4 00000000 */ nop
/* 0031D8 800025D8 8C880000 */ lw $t0, ($a0)
/* 0031DC 800025DC 24060020 */ li $a2, 32
/* 0031E0 800025E0 20840004 */ addi $a0, $a0, 4
.L800025E4:
/* 0031E4 800025E4 0100482A */ slt $t1, $t0, $zero
/* 0031E8 800025E8 11200006 */ beqz $t1, .L80002604
/* 0031EC 800025EC 00000000 */ nop
/* 0031F0 800025F0 832A0000 */ lb $t2, ($t9)
/* 0031F4 800025F4 23390001 */ addi $t9, $t9, 1
/* 0031F8 800025F8 20A50001 */ addi $a1, $a1, 1
/* 0031FC 800025FC 1000000E */ b .L80002638
/* 003200 80002600 A0AAFFFF */ sb $t2, -1($a1)
.L80002604:
/* 003204 80002604 94EA0000 */ lhu $t2, ($a3)
/* 003208 80002608 20E70002 */ addi $a3, $a3, 2
/* 00320C 8000260C 000A5B02 */ srl $t3, $t2, 0xc
/* 003210 80002610 314A0FFF */ andi $t2, $t2, 0xfff
/* 003214 80002614 1160000D */ beqz $t3, .L8000264C
/* 003218 80002618 00AA4822 */ sub $t1, $a1, $t2
/* 00321C 8000261C 216B0002 */ addi $t3, $t3, 2
.L80002620:
/* 003220 80002620 812AFFFF */ lb $t2, -1($t1)
/* 003224 80002624 216BFFFF */ addi $t3, $t3, -1
/* 003228 80002628 21290001 */ addi $t1, $t1, 1
/* 00322C 8000262C 20A50001 */ addi $a1, $a1, 1
/* 003230 80002630 1560FFFB */ bnez $t3, .L80002620
/* 003234 80002634 A0AAFFFF */ sb $t2, -1($a1)
.L80002638:
/* 003238 80002638 00084040 */ sll $t0, $t0, 1
/* 00323C 8000263C 14B8FFE4 */ bne $a1, $t8, .L800025D0
/* 003240 80002640 20C6FFFF */ addi $a2, $a2, -1
/* 003244 80002644 03E00008 */ jr $ra
/* 003248 80002648 00000000 */ nop
.L8000264C:
/* 00324C 8000264C 932B0000 */ lbu $t3, ($t9)
/* 003250 80002650 23390001 */ addi $t9, $t9, 1
/* 003254 80002654 1000FFF2 */ b .L80002620
/* 003258 80002658 216B0012 */ addi $t3, $t3, 0x12
/* 00325C 8000265C 00000000 */ nop

View File

@ -1,15 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osGetCount
/* 007AA0 80006EA0 40024800 */ mfc0 $v0, $9
/* 007AA4 80006EA4 03E00008 */ jr $ra
/* 007AA8 80006EA8 00000000 */ nop

View File

@ -1,61 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osInvalDCache
/* 006E00 80006200 18A0001F */ blez $a1, .L80006280
/* 006E04 80006204 00000000 */ nop
/* 006E08 80006208 240B2000 */ li $t3, 8192
/* 006E0C 8000620C 00AB082B */ sltu $at, $a1, $t3
/* 006E10 80006210 1020001D */ beqz $at, .L80006288
/* 006E14 80006214 00000000 */ nop
/* 006E18 80006218 00804025 */ move $t0, $a0
/* 006E1C 8000621C 00854821 */ addu $t1, $a0, $a1
/* 006E20 80006220 0109082B */ sltu $at, $t0, $t1
/* 006E24 80006224 10200016 */ beqz $at, .L80006280
/* 006E28 80006228 00000000 */ nop
/* 006E2C 8000622C 310A000F */ andi $t2, $t0, 0xf
/* 006E30 80006230 11400007 */ beqz $t2, .L80006250
/* 006E34 80006234 2529FFF0 */ addiu $t1, $t1, -0x10
/* 006E38 80006238 010A4023 */ subu $t0, $t0, $t2
/* 006E3C 8000623C BD150000 */ cache 0x15, ($t0)
/* 006E40 80006240 0109082B */ sltu $at, $t0, $t1
/* 006E44 80006244 1020000E */ beqz $at, .L80006280
/* 006E48 80006248 00000000 */ nop
/* 006E4C 8000624C 25080010 */ addiu $t0, $t0, 0x10
.L80006250:
/* 006E50 80006250 312A000F */ andi $t2, $t1, 0xf
/* 006E54 80006254 11400006 */ beqz $t2, .L80006270
/* 006E58 80006258 00000000 */ nop
/* 006E5C 8000625C 012A4823 */ subu $t1, $t1, $t2
/* 006E60 80006260 BD350010 */ cache 0x15, 0x10($t1)
/* 006E64 80006264 0128082B */ sltu $at, $t1, $t0
/* 006E68 80006268 14200005 */ bnez $at, .L80006280
/* 006E6C 8000626C 00000000 */ nop
.L80006270:
/* 006E70 80006270 BD110000 */ cache 0x11, ($t0)
/* 006E74 80006274 0109082B */ sltu $at, $t0, $t1
/* 006E78 80006278 1420FFFD */ bnez $at, .L80006270
/* 006E7C 8000627C 25080010 */ addiu $t0, $t0, 0x10
.L80006280:
/* 006E80 80006280 03E00008 */ jr $ra
/* 006E84 80006284 00000000 */ nop
.L80006288:
/* 006E88 80006288 3C088000 */ lui $t0, 0x8000
/* 006E8C 8000628C 010B4821 */ addu $t1, $t0, $t3
/* 006E90 80006290 2529FFF0 */ addiu $t1, $t1, -0x10
.L80006294:
/* 006E94 80006294 BD010000 */ cache 1, ($t0)
/* 006E98 80006298 0109082B */ sltu $at, $t0, $t1
/* 006E9C 8000629C 1420FFFD */ bnez $at, .L80006294
/* 006EA0 800062A0 25080010 */ addiu $t0, 0x10
/* 006EA4 800062A4 03E00008 */ jr $ra
/* 006EA8 800062A8 00000000 */ nop

View File

@ -1,46 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osInvalICache
/* 006D50 80006150 18A00011 */ blez $a1, .L80006198
/* 006D54 80006154 00000000 */ nop
/* 006D58 80006158 240B4000 */ li $t3, 16384
/* 006D5C 8000615C 00AB082B */ sltu $at, $a1, $t3
/* 006D60 80006160 1020000F */ beqz $at, .L800061A0
/* 006D64 80006164 00000000 */ nop
/* 006D68 80006168 00804025 */ move $t0, $a0
/* 006D6C 8000616C 00854821 */ addu $t1, $a0, $a1
/* 006D70 80006170 0109082B */ sltu $at, $t0, $t1
/* 006D74 80006174 10200008 */ beqz $at, .L80006198
/* 006D78 80006178 00000000 */ nop
/* 006D7C 8000617C 310A001F */ andi $t2, $t0, 0x1f
/* 006D80 80006180 2529FFE0 */ addiu $t1, $t1, -0x20
/* 006D84 80006184 010A4023 */ subu $t0, $t0, $t2
.L80006188:
/* 006D88 80006188 BD100000 */ cache 0x10, ($t0)
/* 006D8C 8000618C 0109082B */ sltu $at, $t0, $t1
/* 006D90 80006190 1420FFFD */ bnez $at, .L80006188
/* 006D94 80006194 25080020 */ addiu $t0, $t0, 0x20
.L80006198:
/* 006D98 80006198 03E00008 */ jr $ra
/* 006D9C 8000619C 00000000 */ nop
.L800061A0:
/* 006DA0 800061A0 3C088000 */ lui $t0, 0x8000
/* 006DA4 800061A4 010B4821 */ addu $t1, $t0, $t3
/* 006DA8 800061A8 2529FFE0 */ addiu $t1, $t1, -0x20
.L800061AC:
/* 006DAC 800061AC BD000000 */ cache 0, ($t0)
/* 006DB0 800061B0 0109082B */ sltu $at, $t0, $t1
/* 006DB4 800061B4 1420FFFD */ bnez $at, .L800061AC
/* 006DB8 800061B8 25080020 */ addiu $t0, 0x20
/* 006DBC 800061BC 03E00008 */ jr $ra
/* 006DC0 800061C0 00000000 */ nop

View File

@ -1,34 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osMapTLBRdb
/* 0086E0 80007AE0 40085000 */ mfc0 $t0, $10
/* 0086E4 80007AE4 2409001F */ li $t1, 31
/* 0086E8 80007AE8 40890000 */ mtc0 $t1, $0
/* 0086EC 80007AEC 40802800 */ mtc0 $zero, $5
/* 0086F0 80007AF0 240A0017 */ li $t2, 23
/* 0086F4 80007AF4 3C09C000 */ lui $t1, 0xc000
/* 0086F8 80007AF8 40895000 */ mtc0 $t1, $10
/* 0086FC 80007AFC 3C098000 */ lui $t1, 0x8000
/* 008700 80007B00 00095982 */ srl $t3, $t1, 6
/* 008704 80007B04 016A5825 */ or $t3, $t3, $t2
/* 008708 80007B08 408B1000 */ mtc0 $t3, $2
/* 00870C 80007B0C 24090001 */ li $t1, 1
/* 008710 80007B10 40891800 */ mtc0 $t1, $3
/* 008714 80007B14 00000000 */ nop
/* 008718 80007B18 42000002 */ tlbwi
/* 00871C 80007B1C 00000000 */ nop
/* 008720 80007B20 00000000 */ nop
/* 008724 80007B24 00000000 */ nop
/* 008728 80007B28 00000000 */ nop
/* 00872C 80007B2C 40885000 */ mtc0 $t0, $10
/* 008730 80007B30 03E00008 */ jr $ra
/* 008734 80007B34 00000000 */ nop

View File

@ -1,123 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osSetIntMask
/* 005B40 80004F40 400C6000 */ mfc0 $t4, $12
/* 005B44 80004F44 3182FF01 */ andi $v0, $t4, 0xff01
/* 005B48 80004F48 3C088001 */ lui $t0, %hi(__OSGlobalIntMask) # $t0, 0x8001
/* 005B4C 80004F4C 2508AD00 */ addiu $t0, %lo(__OSGlobalIntMask) # addiu $t0, $t0, -0x5300
/* 005B50 80004F50 8D0B0000 */ lw $t3, ($t0)
/* 005B54 80004F54 2401FFFF */ li $at, -1
/* 005B58 80004F58 01614026 */ xor $t0, $t3, $at
/* 005B5C 80004F5C 3108FF00 */ andi $t0, $t0, 0xff00
/* 005B60 80004F60 00481025 */ or $v0, $v0, $t0
/* 005B64 80004F64 3C0AA430 */ lui $t2, %hi(D_A430000C) # $t2, 0xa430
/* 005B68 80004F68 8D4A000C */ lw $t2, %lo(D_A430000C)($t2)
/* 005B6C 80004F6C 11400005 */ beqz $t2, .L80004F84
/* 005B70 80004F70 000B4C02 */ srl $t1, $t3, 0x10
/* 005B74 80004F74 2401FFFF */ li $at, -1
/* 005B78 80004F78 01214826 */ xor $t1, $t1, $at
/* 005B7C 80004F7C 3129003F */ andi $t1, $t1, 0x3f
/* 005B80 80004F80 01495025 */ or $t2, $t2, $t1
.L80004F84:
/* 005B84 80004F84 000A5400 */ sll $t2, $t2, 0x10
/* 005B88 80004F88 004A1025 */ or $v0, $v0, $t2
/* 005B8C 80004F8C 3C01003F */ lui $at, 0x3f
/* 005B90 80004F90 00814024 */ and $t0, $a0, $at
/* 005B94 80004F94 010B4024 */ and $t0, $t0, $t3
/* 005B98 80004F98 000843C2 */ srl $t0, $t0, 0xf
/* 005B9C 80004F9C 3C0A8001 */ lui $t2, %hi(__osRcpImTable)
/* 005BA0 80004FA0 01485021 */ addu $t2, $t2, $t0
/* 005BA4 80004FA4 954A2160 */ lhu $t2, %lo(__osRcpImTable)($t2)
/* 005BA8 80004FA8 3C01A430 */ lui $at, %hi(D_A430000C) # $at, 0xa430
/* 005BAC 80004FAC AC2A000C */ sw $t2, %lo(D_A430000C)($at)
/* 005BB0 80004FB0 3088FF01 */ andi $t0, $a0, 0xff01
/* 005BB4 80004FB4 3169FF00 */ andi $t1, $t3, 0xff00
/* 005BB8 80004FB8 01094024 */ and $t0, $t0, $t1
/* 005BBC 80004FBC 3C01FFFF */ lui $at, (0xFFFF00FF >> 16) # lui $at, 0xffff
/* 005BC0 80004FC0 342100FF */ ori $at, (0xFFFF00FF & 0xFFFF) # ori $at, $at, 0xff
/* 005BC4 80004FC4 01816024 */ and $t4, $t4, $at
/* 005BC8 80004FC8 01886025 */ or $t4, $t4, $t0
/* 005BCC 80004FCC 408C6000 */ mtc0 $t4, $12
/* 005BD0 80004FD0 00000000 */ nop
/* 005BD4 80004FD4 00000000 */ nop
/* 005BD8 80004FD8 03E00008 */ jr $ra
/* 005BDC 80004FDC 00000000 */ nop
.section .rodata
.balign 16
glabel __osRcpImTable
.half 0x0555
.half 0x0556
.half 0x0559
.half 0x055A
.half 0x0565
.half 0x0566
.half 0x0569
.half 0x056A
.half 0x0595
.half 0x0596
.half 0x0599
.half 0x059A
.half 0x05A5
.half 0x05A6
.half 0x05A9
.half 0x05AA
.half 0x0655
.half 0x0656
.half 0x0659
.half 0x065A
.half 0x0665
.half 0x0666
.half 0x0669
.half 0x066A
.half 0x0695
.half 0x0696
.half 0x0699
.half 0x069A
.half 0x06A5
.half 0x06A6
.half 0x06A9
.half 0x06AA
.half 0x0955
.half 0x0956
.half 0x0959
.half 0x095A
.half 0x0965
.half 0x0966
.half 0x0969
.half 0x096A
.half 0x0995
.half 0x0996
.half 0x0999
.half 0x099A
.half 0x09A5
.half 0x09A6
.half 0x09A9
.half 0x09AA
.half 0x0A55
.half 0x0A56
.half 0x0A59
.half 0x0A5A
.half 0x0A65
.half 0x0A66
.half 0x0A69
.half 0x0A6A
.half 0x0A95
.half 0x0A96
.half 0x0A99
.half 0x0A9A
.half 0x0AA5
.half 0x0AA6
.half 0x0AA9
.half 0x0AAA

View File

@ -1,30 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osUnmapTLBAll
/* 006BC0 80005FC0 40085000 */ mfc0 $t0, $10
/* 006BC4 80005FC4 2409001E */ li $t1, 30
/* 006BC8 80005FC8 3C0A8000 */ lui $t2, 0x8000
/* 006BCC 80005FCC 408A5000 */ mtc0 $t2, $10
/* 006BD0 80005FD0 40801000 */ mtc0 $zero, $2
/* 006BD4 80005FD4 40801800 */ mtc0 $zero, $3
.L80005FD8:
/* 006BD8 80005FD8 40890000 */ mtc0 $t1, $0
/* 006BDC 80005FDC 00000000 */ nop
/* 006BE0 80005FE0 42000002 */ tlbwi
/* 006BE4 80005FE4 00000000 */ nop
/* 006BE8 80005FE8 00000000 */ nop
/* 006BEC 80005FEC 2129FFFF */ addi $t1, $t1, -1
/* 006BF0 80005FF0 0521FFF9 */ bgez $t1, .L80005FD8
/* 006BF4 80005FF4 00000000 */ nop
/* 006BF8 80005FF8 40885000 */ mtc0 $t0, $10
/* 006BFC 80005FFC 03E00008 */ jr $ra
/* 006C00 80006000 00000000 */ nop

View File

@ -1,46 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osWritebackDCache
/* 0052C0 800046C0 18A00011 */ blez $a1, .L80004708
/* 0052C4 800046C4 00000000 */ nop
/* 0052C8 800046C8 240B2000 */ li $t3, 8192
/* 0052CC 800046CC 00AB082B */ sltu $at, $a1, $t3
/* 0052D0 800046D0 1020000F */ beqz $at, .L80004710
/* 0052D4 800046D4 00000000 */ nop
/* 0052D8 800046D8 00804025 */ move $t0, $a0
/* 0052DC 800046DC 00854821 */ addu $t1, $a0, $a1
/* 0052E0 800046E0 0109082B */ sltu $at, $t0, $t1
/* 0052E4 800046E4 10200008 */ beqz $at, .L80004708
/* 0052E8 800046E8 00000000 */ nop
/* 0052EC 800046EC 310A000F */ andi $t2, $t0, 0xf
/* 0052F0 800046F0 2529FFF0 */ addiu $t1, $t1, -0x10
/* 0052F4 800046F4 010A4023 */ subu $t0, $t0, $t2
.L800046F8:
/* 0052F8 800046F8 BD190000 */ cache 0x19, ($t0)
/* 0052FC 800046FC 0109082B */ sltu $at, $t0, $t1
/* 005300 80004700 1420FFFD */ bnez $at, .L800046F8
/* 005304 80004704 25080010 */ addiu $t0, $t0, 0x10
.L80004708:
/* 005308 80004708 03E00008 */ jr $ra
/* 00530C 8000470C 00000000 */ nop
.L80004710:
/* 005310 80004710 3C088000 */ lui $t0, 0x8000
/* 005314 80004714 010B4821 */ addu $t1, $t0, $t3
/* 005318 80004718 2529FFF0 */ addiu $t1, $t1, -0x10
.L8000471C:
/* 00531C 8000471C BD010000 */ cache 1, ($t0)
/* 005320 80004720 0109082B */ sltu $at, $t0, $t1
/* 005324 80004724 1420FFFD */ bnez $at, .L8000471C
/* 005328 80004728 25080010 */ addiu $t0, 0x10
/* 00532C 8000472C 03E00008 */ jr $ra
/* 005330 80004730 00000000 */ nop

View File

@ -1,23 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel osWritebackDCacheAll
/* B7D630 80106490 3C088000 */ lui $t0, 0x8000
/* B7D634 80106494 240A2000 */ li $t2, 8192
/* B7D638 80106498 010A4821 */ addu $t1, $t0, $t2
/* B7D63C 8010649C 2529FFF0 */ addiu $t1, $t1, -0x10
.L801064A0:
/* B7D640 801064A0 BD010000 */ cache 1, ($t0)
/* B7D644 801064A4 0109082B */ sltu $at, $t0, $t1
/* B7D648 801064A8 1420FFFD */ bnez $at, .L801064A0
/* B7D64C 801064AC 25080010 */ addiu $t0, 0x10
/* B7D650 801064B0 03E00008 */ jr $ra
/* B7D654 801064B4 00000000 */ nop

View File

@ -1,18 +0,0 @@
/*
* The Legend of Zelda: Ocarina of Time ROM header
*/
.byte 0x80, 0x37, 0x12, 0x40 /* PI BSD Domain 1 register */
.word 0x0000000F /* Clockrate setting */
.word 0x80000400 /* Entrypoint function (`entrypoint`) */
.word 0x0000144C /* Revision */
.word 0x917D18F6 /* Checksum 1 */
.word 0x69BC5453 /* Checksum 2 */
.word 0x00000000 /* Unknown */
.word 0x00000000 /* Unknown */
.ascii "THE LEGEND OF ZELDA " /* Internal ROM name */
.word 0x00000000 /* Unknown */
.word 0x0000004E /* Cartridge */
.ascii "ZL" /* Cartridge ID */
.ascii "P" /* Region */
.byte 0x0F /* Version */

View File

@ -1 +0,0 @@
f0b7f35375f9cc8ca1b2d59d78e35405 zelda_ocarina_mq_dbg.z64

View File

@ -1,85 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .bss
.balign 16
glabel D_8016BAD0
.space 0x1B0
glabel D_8016BC80
.space 0x240
glabel D_8016BEC0
.space 0x420
glabel D_8016C2E0
.space 0x3C0
glabel D_8016C6A0
.space 0x180
glabel D_8016C820
.space 0x90
glabel D_8016C8B0
.space 0xF0
glabel sSoundRequests
.space 0x1800
glabel sSoundBankListEnd
.space 0x8
glabel sSoundBankFreeListStart
.space 0x8
glabel sSoundBankUnused
.space 0x8
glabel gActiveSounds
.space 0xA8
glabel sCurSfxPlayerChannelIdx
.space 0x4
glabel gSoundBankMuted
.space 0xC
glabel sUnusedBankLerp
.space 0x70
glabel gAudioSfxSwapSource
.space 0x18
glabel gAudioSfxSwapTarget
.space 0x18
glabel gAudioSfxSwapMode
.space 0x10
glabel D_8016E320
.space 0x28
glabel D_8016E348
.space 0x8
glabel sAudioSeqCmds
.space 0x400
glabel D_8016E750
.space 0x990
glabel D_8016F0E0 # unused?
.space 0xA0
glabel gAudioContext
.space 0x6450
glabel D_801755D0
.space 0x20

View File

@ -1,104 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
.balign 16
glabel sSeqCmdWrPos
.incbin "baserom.z64", 0xBAA5A0, 0x4
glabel sSeqCmdRdPos
.incbin "baserom.z64", 0xBAA5A4, 0x4
glabel D_80133408
.incbin "baserom.z64", 0xBAA5A8, 0x4
glabel D_8013340C
.incbin "baserom.z64", 0xBAA5AC, 0x4
glabel D_80133410
.incbin "baserom.z64", 0xBAA5B0, 0x4
glabel gAudioSpecId
.incbin "baserom.z64", 0xBAA5B4, 0x4
glabel D_80133418
.incbin "baserom.z64", 0xBAA5B8, 0x8
glabel D_80133420
.incbin "baserom.z64", 0xBAA5C0, 0x48
glabel D_80133468
.incbin "baserom.z64", 0xBAA608, 0x48
glabel D_801334B0
.incbin "baserom.z64", 0xBAA650, 0x90
glabel D_80133540
.incbin "baserom.z64", 0xBAA6E0, 0x48
glabel D_80133588
.incbin "baserom.z64", 0xBAA728, 0x48
glabel D_801335D0
.incbin "baserom.z64", 0xBAA770, 0x48
glabel D_80133618
.incbin "baserom.z64", 0xBAA7B8, 0x48
glabel D_80133660
.incbin "baserom.z64", 0xBAA800, 0x48
glabel D_801336A8
.incbin "baserom.z64", 0xBAA848, 0x48
glabel D_801336F0
.incbin "baserom.z64", 0xBAA890, 0x48
glabel D_80133738
.incbin "baserom.z64", 0xBAA8D8, 0x90
glabel gAudioSpecs
.incbin "baserom.z64", 0xBAA968, 0xC
.word D_80133420
.incbin "baserom.z64", 0xBAA978, 0x34
.word D_80133468
.incbin "baserom.z64", 0xBAA9B0, 0x34
.word D_801334B0
.incbin "baserom.z64", 0xBAA9E8, 0x34
.word D_80133540
.incbin "baserom.z64", 0xBAAA20, 0x34
.word D_80133588
.incbin "baserom.z64", 0xBAAA58, 0x34
.word D_801335D0
.incbin "baserom.z64", 0xBAAA90, 0x34
.word D_80133618
.incbin "baserom.z64", 0xBAAAC8, 0x34
.word D_80133660
.incbin "baserom.z64", 0xBAAB00, 0x34
.word D_801336A8
.incbin "baserom.z64", 0xBAAB38, 0x34
.word D_80133660
.incbin "baserom.z64", 0xBAAB70, 0x34
.word D_801336F0
.incbin "baserom.z64", 0xBAABA8, 0x34
.word D_80133738
.incbin "baserom.z64", 0xBAABE0, 0x34
.word D_80133738
.incbin "baserom.z64", 0xBAAC18, 0x34
.word D_80133420
.incbin "baserom.z64", 0xBAAC50, 0x34
.word D_80133660
.incbin "baserom.z64", 0xBAAC88, 0x34
.word D_80133420
.incbin "baserom.z64", 0xBAACC0, 0x34
.word D_80133420
.incbin "baserom.z64", 0xBAACF8, 0x34
.word D_801334B0
.incbin "baserom.z64", 0xBAAD30, 0x30

View File

@ -1,25 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .bss
.balign 16
glabel sFaultStructPtr
.space 4
glabel sFaultIsWaitingForInput
.space 4
glabel sFaultStack
.space 0x600
glabel sFaultThreadInfo
.space 0x20
glabel gFaultStruct
.space 0x850

View File

@ -1,38 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .rodata
.balign 16
glabel gSoundFontTable
.incbin "baserom.z64", 0xBCC270, 0x270
glabel gSequenceFontTable
.incbin "baserom.z64", 0xBCC4E0, 0x1C0
glabel gSequenceTable
.incbin "baserom.z64", 0xBCC6A0, 0x6F0
glabel gSampleBankTable
.incbin "baserom.z64", 0xBCCD90, 0x80
glabel rspAspMainDataStart
.incbin "baserom.z64", 0xBCCE10, 0x2E0
glabel rspAspMainDataEnd
glabel D_80155F50
.incbin "baserom.z64", 0xBCD0F0, 0x1630
glabel D_80157580
.incbin "baserom.z64", 0xBCE720, 0x420
glabel D_801579A0
.incbin "baserom.z64", 0xBCEB40, 0x390
glabel gJpegUCodeData
.incbin "baserom.z64", 0xBCEED0, 0x60

View File

@ -1,19 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel D_801120C0
.incbin "baserom.z64", 0xB89260, 0xFB0
glabel D_80113070
.incbin "baserom.z64", 0xB8A210, 0x18C0
glabel gJpegUCode
.incbin "baserom.z64", 0xB8BAD0, 0xAF0

View File

@ -1,16 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .text
.balign 16
glabel D_80009320
.incbin "baserom.z64", 0x9F20, 0xD0
glabel D_800093F0
.incbin "baserom.z64", 0x9FF0, 0x20

View File

@ -1,21 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
.balign 16
# Unused
glabel D_80009410
.word osStopThread
.word __osSetHWIntrRoutine
.word __osSetFpcCsr
.word __osGetFpcCsr
.word __osGetHWIntrRoutine
.word __osSetHWIntrRoutine
.word osViGetNextFramebuffer
.word bcmp

View File

@ -1,25 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
.balign 16
# Unused
glabel D_8012ABC0
.word func_801067F0 # fmodf?
.word guScale
.word guRotate
.word guTranslate
.word GfxPrint_SetPos
.word GfxPrint_SetColor
.word GfxPrint_Printf
.word GfxPrint_SetPosPx
.word GfxPrint_Init
.word GfxPrint_Open
.word GfxPrint_Close
.word GfxPrint_Destroy

View File

@ -1,18 +0,0 @@
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
.balign 16
# temporary file name, rename to something more appropriate when decompiled
glabel gMojiFontTLUTs
.incbin "baserom.z64", 0xBA18E0, 0x80
glabel gMojiFontTex
.incbin "baserom.z64", 0xBA1960, 0x400

View File

@ -1,11 +0,0 @@
version: "3"
services:
oot:
volumes:
- oot-sync:/oot:nocopy
image: "oot:latest"
tty: true
volumes:
oot-sync:
external: true

View File

@ -1,42 +0,0 @@
# Building mips-linux-binutils on Windows using Cygwin
First, you will need to install the following packages using the Cygwin installer:
- make
- gcc-g++
- bison
- flex
- texinfo
- binutils (Make sure to check the "Src?" checkbox since we're interested in the source code. Once the download is finished, you will find it in `/usr/src/`)
Create destination dir for binutils
```bash
sudo mkdir -p /opt/cross
```
Extract binutils source
```bash
cd /usr/src/binutils-[...].src/
tar xjf binutils-[...].tar.bz2
```
Create and enter build dir
```bash
mkdir build-binutils
cd build-binutils
```
Configure the build
```bash
../binutils-gdb/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-gprof --disable-nls --disable-werror --disable-gdb --disable-libdecnumber --disable-readline --disable-sim
```
Make and install binutils
```bash
make -j
sudo make install -j
```
Add the new binutils binaries to your system PATH:
You can do that by adding `PATH=$PATH:/opt/cross/bin` to `~/.bashrc` and then reloading `~/.bashrc`.
Alternatively you can edit the `Path` variable in `Edit the system environment variables`>`Environment Variables` (in which case you will need to relaunch your terminal).

View File

@ -1,47 +0,0 @@
# Building mips-linux-binutils on MacOS
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
wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.bz2
tar xjf binutils-2.35.tar.bz2
```
Create and enter build dir
```bash
mkdir build-binutils
cd build-binutils
```
Configure the build
```bash
../binutils-2.35/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-gprof --disable-gdb --disable-werror
```
Make and install binutils
```bash
make -j
sudo make install
```
Edit your ~/.bash_profile 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
```

View File

@ -1,100 +0,0 @@
# Documentation Style Guide
This project uses [Doxygen](https://www.doxygen.nl/index.html) to generate documentation pages from comments found in the source files. This guide focuses on writing compatible comments and ensuring consistency across the codebase.
```diff
- Note -
As the codebase is constantly changing, only document what is complete, well-understood and not
already covered by good naming. This is especially true for function parameters and return values.
Also note that there is no obligation to completing the documentation steps for functions you
work on if you do not want to at the time.
```
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`.
## Documenting Functions
For functions, a description of the function's purpose should go above the function:
```c
/**
* My description of this function
*/
void foo(void);
```
Further considerations:
- Any comments inside the function should follow the usual `//` or `/**/` comment styles.
- For documenting return values, place a `@return` at the bottom of the function comment followed by the description of the return value. This should only be done if the name of the function is not self-explanatory and is well-understood.
- For documenting parameters, place a `@param` between the comment and the @return (if applicable) followed by the name of the parameter and a brief description. This should only be done if the name of the parameter is not self-explanatory and is well-understood.
- All `@param`s should come before `@return` and be in the same order the parameters appear in the function declaration. Note that this does not mean you should add empty `@params` for parameters deemed self-explanatory.
A full example would be as follows: (however in practice functions such as this would be considered self-explanatory)
```c
/**
* This is an example
*
* @param bar the input
* @return bar multiplied by 2
*/
s32 foo(s32 bar) {
return 2*bar;
}
```
## Documenting Variables
Documentation of variables should include what this variable is used for if the name is not completely clear and if applicable whether a set of defines or enumerations should be used alongside it (which should be linked with `@see`, see below)
```c
/**
* My description of this variable
*/
s32 foo;
```
## Documenting Files
File documentation should go near the top of the file, below includes. It should only feature information that is general to the file.
```c
/**
* @file file_name.c
*
* My description of this file
*/
```
## Other
### Documenting Bugs:
Bugs should be documented on the line above where the bug begins.
```c
//! @bug description
```
### Linking related information:
`@see` should be used to provide links to related information where appropriate, for example:
```c
/**
* Save File Data
* @see SaveContext
*/
SaveContext gSaveContext;
```
In the case of functions, `@see` should come before the first `@param`.
### HTML
You can include html tags in your doc comments, however it is strongly advised against doing this if it greatly reduces readability of the code comments.
```c
/**
* My<br>
* Newline<br>
* Doc Comment
*/
```
### LaTeX
You can embed [LaTeX](https://wikipedia.org/wiki/LaTeX) in your doc comments if useful to do so.
For inline rendering:
```c
/**
* \f$ \textrm{Your LaTeX Here} \f$
*/
```
For centered rendering on a separate line:
```c
/**
* \f[ \textrm{Your LaTeX Here} \f]
*/
```

View File

@ -1,11 +0,0 @@
import re
import sys
global_asm_regex = re.compile(r"#pragma GLOBAL_ASM((.)*)")
def repl_global_asm(cap):
return "/// " + cap.group(0).replace("#pragma ","") + "\n? " + cap.group(0).split("/")[-1].split(".s")[0] + "(?);"
with open(sys.argv[1], 'r') as infile:
sys.stdout.write(re.sub(global_asm_regex, repl_global_asm, infile.read()))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,926 +0,0 @@
# Beginning decompilation: the Init function and the Actor struct
Up: [Contents](contents.md)
Open the C file and the H file with your actor's name from the appropriate directory in `src/overlays/actors/`. These will be the main files we work with. We will be using EnJj (Lord Jabu Jabu) as our example: despite being a fairly small actor, it has a number of interesting features.
Each actor has associated to it a data file and one assembly file per function. During the process, we will transfer the contents of all or most of these into the main C file. VSCode's search feature usually makes it quite easy to find the appropriate files without troubling the directory tree.
## Anatomy of the C file
The actor file starts off looking like:
![Fresh actor file annotated](images/fresh_actor_file_annotated.png)
It is currently divided into six sections as follows:
1. Preliminary description of the actor. This is not present for all actors, but gives a short description based on what we know about the actor already. It may be inaccurate, so feel free to correct it after you understand the actor better.
2. Specific `include`s and `define`s for the actor. You may need to add more header files, but otherwise this section is unlikely to change.
3. These are prototypes for the "main four" functions that almost every actor has. You add more functions here if they need to be declared above their first use.
4. A set of `extern`s. These refer to data that comes from other files, usually in the actor's corresponding object file. They point to addresses in the ROM where assets are stored (usually collision data, animations or display lists). Once the corresponding object files have been decompiled, these will simply be replaced by including the object file (see [Object Decompilation](object_decomp.md) for how this process works). For now, you can put them between blocks 5 and 6 to conform with how the rest of our files are structured. These symbols have been automatically extracted from the MIPS code. There may turn out to be some that were not caught by the script, in which case they need to be placed in the file called `undefined_syms.txt` in the root directory of the project. Ask in Discord for how to do this: it is simple, but rare enough to not be worth covering here.
5. Commented-out section containing the `InitVars`. This can be ignored until we import the data: it is a section of the actor data that has been imported automatically since, unlike most of the data, it has the same format in every actor. (This image is out of date: actors now also have their ColliderInits in here)
6. List of functions. Each `#pragma` is letting the compiler use the corresponding assembly file while we do not have decompiled C code for that function. The majority of the decompilation work is converting these functions into C that it looks like a human wrote.
## Header file
The header file looks like this at the moment:
![Fresh actor header](images/fresh_actor_header.png)
The struct currently contains a variable that is the `Actor` struct, which all actors use one way or another, plus other items. Currently we don't know what those items are, so we have an array of chars as padding instead, just so the struct is the right size. As we understand the actor better, we will be able to gradually replace this padding with the actual variables that the actor uses.
The header file is also used to declare structs and other information about the actor that is needed globally (e.g. by other actors).
## Order of decompilation
The general rule for order of decompilation is
- Start with `Init`, because it usually contains the most information about the structure of the actor.
- Next, decompile any other functions from the actor you have found in `Init`. You generally start with the action functions, because they return nothing and all take the same arguments,
```C
void func_80whatever(EnJj* this, GlobalContext* globalCtx);
```
- Decompile each action function in turn until you run out. Along the way, do any other functions in the actor for which you have discovered the argument types. (You are probably better doing depth-first on action functions than breadth-first: it's normally easier to follow along one branch of the actions than )
- After you've run out, do `Update`. This usually provides the rest of the function tree, apart from posibly some Draw functions.
- Finally, do the draw functions.
The above is a rough ordering for the beginner. As you become more experienced, you can deviate from this scheme, but the general principle remains that you should work on functions that you already know something about.
## Data
![Fresh actor data](images/fresh_actor_data.png)
Associated to each actor is a `.data` file, containing data that the actor uses. This ranges from spawn positions, to display lists, to even some cutscene data. Since the structure of the data is very inconsistent between actors, automatic importing has been very limited, so the vast majority must be done manually.
There are two ways of transfering the data into an actor: we can either
- import it all naively as words (`s32`s), which will still allow it to compile, and sort out the actual types later, or
- we can extern each piece of data as we come across it, and come back to it later when we have a better idea of what it is.
We will concentrate on the second here; the other is covered in [the document about data](data.md). Thankfully this means we essentially don't have to do anything to the data yet. Nevertheless, it is often quite helpful to copy over at least some of the data and leave it commented out for later replacement. *Data must go in the same order as in the data file, and data is "all or nothing": you cannot only import some of it*.
![Data copied in and commented out](images/data_inserted_commented_out.png)
**WARNING** The way in which the data was extracted from the ROM means that there are sometimes "fake symbols" in the data, which have to be removed to avoid confusing the compiler. Thankfully it will turn out that this is not the case here, although there will be other data issues.
(Sometimes it is useful to import the data in the middle of doing functions: you just have to choose an appropriate moment.)
Some actors also have a `.bss` file. This is just data that is initialised to 0, and can be imported immediately once you know what type it is, by declaring it without giving it a value.
## Init
The Init function sets up the various components of the actor when it is first loaded. It is hence usually very useful for finding out what is in the actor struct, and so we usually start with it. (Some people like starting with Destroy, which is usually shorter and simpler, but gives some basic information about the actor, but Init is probably best for beginners.)
### mips2c
The first stage of decompilation is done by a program called mips2c or mips_to_c, which constructs a C interpretation of the assembly code based on reading it very literally. This means that considerable cleanup will be required to turn it into something that firstly compiles at all, and secondly looks like a human wrote it, let alone a Zelda developer from the late '90s.
The web version of mips2c can be found [here](https://simonsoftware.se/other/mips_to_c.py). There is also a downloadable version, but let's just use the online one for now.
Since the actor depends on the rest of the codebase, we can't expect to get much intelligible out of mips2c without giving it some context. We make this using a Python script in the `tools` directory called `m2ctx.py`, so run
```
$ ./tools/m2ctx.py <path_to_c_file>
```
from the main directory of the repository. In this case, the C file is `src/overlays/actors/ovl_En_Jj/z_en_jj.c`. This generates a file called `ctx.c` in the main directory of the repository. Open this file in a text editor (Notepad will do) and copy the whole contents into the "Existing C source, preprocessed" box.
![Copying the context](images/ctx.png)
Now, open the file containing the assembly for `EnJj_Init`.
![Copying the Init asm](images/init_asm.png)
Copy the entire contents of this file into the upper box, labelled "MIPS assembly". Now, for Init (and also the other "main 4" functions `Destroy`, `Update` and `Draw`), the function's first argument is `Actor* thisx`. But we would like mips2c to use the fields in the actual actor struct; we can make it do this by deliberately changing the prototype of the `EnJj_Init` in the pasted context to have first argument `EnJj* this` instead.
![Changing init prototype](images/changing_init_prototype.png)
Now press "Decompile". This should produce C code:
```C
void EnJj_Init(EnJj *this, GlobalContext *globalCtx) {
CollisionHeader *sp4C;
DynaCollisionContext *sp44;
DynaCollisionContext *temp_a1;
DynaCollisionContext *temp_a1_2;
DynaCollisionContext *temp_a1_3;
char *temp_v0_2;
s16 temp_v0;
sp4C = NULL;
Actor_ProcessInitChain((Actor *) this, &D_80A88CE0);
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
temp_v0 = this->actor.params;
temp_a1 = this + 0x164;
[...]
```
Typically for all buth the simplest functions, there is a lot that needs fixing before we are anywhere near seeing how close we are to the original code. You will notice that mips2c creates a lot of temporary variables. Usually most of these will turn out to not be real, and we need to remove the right ones to get the code to match.
First, change the first argument back to `Actor* thisx` so that the function matches its prototype above. To allow the function to find the variables, we need another correction. Half of this has already been done at the top of the function, where we have
```C
#define THIS ((EnJj*)thisx)
```
To do the other half, write the following at the beginning of the function, before any declarations:
```C
EnJj* this = THIS;
```
Now everything points to the right place, even though the argument of the function seems inconsistent with the contents.
(This step is only necessary for the "main 4" functions, and sometimes functions that are used by these: it relates to how such functions are used outside the actor.)
While we are carrying out initial changes, you can also find-and-replace any instances of `(Actor *) this` by `&this->actor`. The function now looks like this:
<details>
<summary>
Large code block, click to show.
</summary>
```C
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
EnJj* this = THIS;
CollisionHeader *sp4C;
DynaCollisionContext *sp44;
DynaCollisionContext *temp_a1;
DynaCollisionContext *temp_a1_2;
DynaCollisionContext *temp_a1_3;
char *temp_v0_2;
s16 temp_v0;
sp4C = NULL;
Actor_ProcessInitChain(&this->actor, &D_80A88CE0);
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
temp_v0 = this->actor.params;
temp_a1 = this + 0x164;
if (temp_v0 == -1) {
sp44 = temp_a1;
SkelAnime_InitFlex(globalCtx, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
Animation_PlayLoop((SkelAnime *) sp44, (AnimationHeader *) &D_06001F4C);
this->unk30A = (u16)0;
this->unk30E = (u8)0;
this->unk30F = (u8)0;
this->unk310 = (u8)0;
this->unk311 = (u8)0;
if ((*(&gSaveContext + 0xEDA) & 0x400) != 0) {
func_80A87800(this, &func_80A87BEC);
} else {
func_80A87800(this, &func_80A87C30);
}
this->unk300 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, (u16)0x5A, this->actor.world.pos.x - 10.0f, this->actor.world.pos.y, this->actor.world.pos.z, 0, (?32) this->actor.world.rot.y, 0, 0);
DynaPolyActor_Init((DynaPolyActor *) this, 0);
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
temp_a1_3 = this + 0x2B0;
sp44 = temp_a1_3;
Collider_InitCylinder(globalCtx, (ColliderCylinder *) temp_a1_3);
Collider_SetCylinder(globalCtx, (ColliderCylinder *) temp_a1_3, &this->actor, &D_80A88CB4);
this->actor.colChkInfo.mass = 0xFF;
return;
}
if (temp_v0 == 0) {
DynaPolyActor_Init((DynaPolyActor *) this, 0);
CollisionHeader_GetVirtual((void *) &D_06001830, &sp4C);
temp_a1_2 = &globalCtx->colCtx.dyna;
sp44 = temp_a1_2;
temp_v0_2 = DynaPoly_SetBgActor(globalCtx, temp_a1_2, &this->actor, sp4C);
this->unk_14C = temp_v0_2;
func_8003ECA8(globalCtx, temp_a1_2, (s32) temp_v0_2);
this->actor.update = &func_80A87F44;
this->actor.draw = NULL;
Actor_SetScale(&this->actor, 0.087f);
return;
}
if (temp_v0 != 1) {
return;
}
DynaPolyActor_Init((DynaPolyActor *) this, 0);
CollisionHeader_GetVirtual((void *) &D_0600BA8C, &sp4C);
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
this->actor.update = &func_80A87F44;
this->actor.draw = NULL;
Actor_SetScale(&this->actor, 0.087f);
}
```
</details>
In the next sections, we shall sort out the various initialisation functions that occur in Init. There are several types, and one of the reasons we are using EnJj as the example is that it has several of the most common ones. A disadvantage of this actor is that it has an unusually complicated Init: we can see that it does three different things depending on the value of its params.
### Init chains
Almost always, one of the first items in `Init` is a function that looks like
```C
Actor_ProcessInitChain(&this->actor, &D_80A88CE0);
```
which initialises common properties of actor using an InitChain, which is usually somewhere near the top of the data, in this case in the variable `D_80A88CE0`. Although we don't need to do this now since we we will extern the data, we might as well work out what it is now. Fortunately, we have a script to do this.
The InitChain script is also in the tools directory, and is called `ichaindis.py`. Simply passing it the ROM address will spit out the entire contents of the InitChain, in this case:
```
$ ./tools/ichaindis.py baserom.z64 80A88CE0
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(unk_50, 87, ICHAIN_CONTINUE),
ICHAIN_F32(unk_F4, 4000, ICHAIN_CONTINUE),
ICHAIN_F32(unk_F8, 3300, ICHAIN_CONTINUE),
ICHAIN_F32(unk_FC, 1100, ICHAIN_STOP),
};
```
However, some of these variables have now been given names in the Actor struct. Pass it `--names` to fill these in automatically:
```
$ ./tools/ichaindis.py --names baserom.z64 80A88CE0
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
};
```
Replace the commented-out .words for the `glabel D_80A88CE0` with this, and comment it out, instead adding
```C
extern InitChainEntry D_80A88CE0[];
```
above it:
```C
extern InitChainEntry D_80A88CE0[];
// static InitChainEntry sInitChain[] = {
// ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
// };
```
(We will come back and actually import it after doing the rest of the actor.)
Since this is an array, we do not need the `&` in the function any more, which leaves us with
```C
Actor_ProcessInitChain(&this->actor, D_80A88CE0);
```
in `EnJj_Init`.
### DynaPoly
Glancing through the rest of `EnJj_Init`, we notice some references to DynaPoly, for example
```C
DynaPolyActor_Init((DynaPolyActor *) this, 0);
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
```
This means that EnJj is not an ordinary actor: it is instead a DynaPoly actor. In-game this is to do with how the actor interacts with Link and the environment (a good rule of thumb is that Link can often stand on DynaPoly actors as if they were ground). For decompilation purposes, it means that the actor struct is wrong: the first element of a DynaPoly actor's struct is not an `Actor` struct, but a `DynaPolyActor`, usually called `dyna`. We should fix this immediately to avoid confusion later. (Some actors have this correctly identified already; we were unlucky with this one.)
Since there's basically nothing in the struct at present, the change is easy to make: replace `Actor actor` with `DynaPolyActor dyna`. Now, `DynaPolyActor` is a different size to `Actor`, so we need to account for that. To find out what size it is, you need to find the definition. In VSCode you can usually Ctrl+Left Click on things to go to where they are defined. Doing so takes us to `z64actor.h`, where most actor-related structs are defined: we find
```C
typedef struct {
/* 0x000 */ Actor actor;
/* 0x14C */ u32 bgId;
/* 0x150 */ f32 unk_150;
/* 0x154 */ f32 unk_154;
/* 0x158 */ s16 unk_158;
/* 0x15A */ u16 unk_15A;
/* 0x15C */ u32 unk_15C;
/* 0x160 */ u8 unk_160;
/* 0x162 */ s16 unk_162;
} DynaPolyActor; // size = 0x164
```
so a `DynaPolyActor` struct is an `Actor` with various other things after it. For now all we care about is the size, i.e. `0x164`. This tells us that the next thing after the `DynaPolyActor` struct in the `EnJj` struct begins at `0x164`, not `0x14C` as it does for `Actor`s.
So rename the variable to `unk_164` and change the comment to say `0x0164` (the comments don't do anything, they just make it easier to keep track of where everything is when it's named).
Next we need to adjust the size of the array so that the struct is still the right size. In this case, we just subtract the address of the padding variable from the total size of the struct:
```0x314 - 0x164 = 1B0```. Hence the struct is now
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ char unk_164[0x1B0];
} EnJj; // size = 0x0314
```
Now that we know this, it is worth remaking the context file and running mips2c again, since we have changed the struct significantly. Doing so, and replacing `(Actor*) this` with `&this->dyna.actor` this time, we find that the block we quoted above has become
```C
DynaPolyActor_Init((DynaPolyActor *) this, 0);
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
```
Next, replace `(DynaPolyActor *) this` by `&this->dyna`. There's not a lot more we can do to the DynaPoly stuff right now, so just remove the casts to void and move on.
### Colliders
The next common thing that actors have is colliders. Not every actor has these, but most do, even if they don't just use them for collision system purposes.
The relevant functions in this actor are
```C
temp_a1_3 = this + 0x2B0;
sp44 = temp_a1_3;
Collider_InitCylinder(globalCtx, (ColliderCylinder *) temp_a1_3);
Collider_SetCylinder(globalCtx, (ColliderCylinder *) temp_a1_3, &this->dyna.actor, &D_80A88CB4);
```
Notice that `sp44` is set, but actually not used anywhere in the actor. This is a good indication that it is fake. We'll get back to that. Similarly, `temp_a1_3` is only used in these functions, so is likely to be fake as well: it's simply trying to get the pointer into the `a1` register.
Since mips2c doesn't know about the collider, it has just told us where it is, namely `this + 0x2B0`. So insert a `ColliderCylinder collider` variable in the actor struct, look up its size, and redo the padding. This should give
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ char unk_164[0x14C];
/* 0x02B0 */ ColliderCylinder collider;
/* 0x02FC */ char unk_2FC[0x18];
} EnJj; // size = 0x0314
```
Now replace the temps, so we have
```C
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
```
(You may prefer to just comment out temps initially, to keep track of where they were.)
The last thing we need to deal with is the last variable of `Collider_SetCylinder`, which is again data.
<!--Also again we have a script to translate the raw data. This one is called `colliderinit.py`, and lives in `tools/overlayhelpers`. It takes the VRAM address of the data and the type of collider (for more info on use, pass it `-h`). We find
```
$ ./tools/overlayhelpers/colliderinit.py 80A88CB4 ColliderCylinderInit
ovl_En_Jj: Rom 00E3E3D0:00E3F9E0 VRam 80A87800:80A88E10 Offset 0014B4
static ColliderCylinderInit sCylinderInit =
{
{ COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
{ 170, 150, 0, { 0, 0, 0 } },
};
```
As with the InitChain, replace the commented-out data we copied into the C file with this:
```C
extern ColliderCylinderInit D_80A88CB4;
// static ColliderCylinderInit sCylinderInit =
// {
// { COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
// { 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
// { 170, 150, 0, { 0, 0, 0 } },
// };
```-->
This is already in the actor file in the correct format, all you need to do is add an extern for it underneath:
```C
/*
[...]
*/
extern ColliderCylinderInit D_80A88CB4;
```
Unlike the InitChain, this is not an array, so keep the `&` in the function.
### SkelAnime
This is the combined system that handles actors' skeletons and their animations. It is the other significant part of most actor structs. We see its initialisation in this part of the code:
```C
temp_a1 = this->unk_164;
...
sp44 = (DynaCollisionContext *) temp_a1;
SkelAnime_InitFlex(globalCtx, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
Animation_PlayLoop((SkelAnime *) sp44, (AnimationHeader *) &D_06001F4C);
```
(Both of the temps are likely to be fake.)
An actor with SkelAnime has three structs in the Actor struct that handle it: one called SkelAnime, and two arrays of `Vec3s`, called `jointTable` and `overrideDrawTable` (for now). Usually, although not always, they are next to one another.
There are two different sorts of SkelAnime, although for decompilation purposes there is not much difference between them. From `SkelAnime_InitFlex` we can read off that
- The `SkelAnime` struct is at `this + 0x164`
- The `jointTable` is at `this + 0x1A8`
- The `overrideDrawTable` is at `this + 0x22C`
- The number of limbs is `0x16 = 22`
- Hence the `jointTable` and `overrideDrawTable` both have `22` elements
Looking in `z64animation.h`, we find that `SkelAnime` has size `0x44`, and looking in `z64math.h`, that `Vec3s` has size `0x6`. Since ` 0x164 + 0x44 = 0x1A8 `, `jointTable` is immediately after the `SkelAnime`, and since `0x1A8 + 0x6 * 0x16 = 0x22C`, `overrideDrawTable` is immediately after the `jointTable`. Finally, `0x22C + 0x6 * 0x16 = 2B0`, and we have filled all the space between the `dyna` and `collider`. Therefore the struct now looks like
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ SkelAnime skelAnime;
/* 0x01A8 */ Vec3s jointTable[22];
/* 0x022C */ Vec3s overrideDrawTable[22];
/* 0x02B0 */ ColliderCylinder collider;
/* 0x02FC */ char unk_2FC[0x18];
} EnJj; // size = 0x0314
```
The last information we get from the SkelAnime functions is the types of two of the externed symbols: `D_0600B9A8` is a `FlexSkeletonHeader`, and `D_06001F4C` is an `AnimationHeader`. So we can change these in the C file:
```C
extern UNK_TYPE D_06000A1C;
extern UNK_TYPE D_06001830;
extern AnimationHeader D_06001F4C;
extern FlexSkeletonHeader D_0600B9A8;
extern UNK_TYPE D_0600BA8C;
```
and removing the temps,
```C
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
```
### More struct variables
This function also gives us information about other things in the struct. One obvious thing that sticks out is
```C
this->unk300 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, (u16)0x5A, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, (?32) this->dyna.actor.world.rot.y, 0, 0);
```
Hovering over this function tells us it outputs a pointer to the spawned actor, so `this->unk_300` is an `Actor*`. We may or may not care what this actor actually is, depending on how it is used later on, so let's just add `/* 0x0300 */ Actor* childActor` to the struct for now.
We can look up what the actor with ID 0x5A is in `z64actor.h`: we find it is `ACTOR_EN_JJ`. So some Jabus spawn another Jabu. Filling this in and removing the spurious cast, we have
```C
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
```
Finally, we have this block:
```C
this->unk30A = (u16)0;
this->unk30E = (u8)0;
this->unk30F = (u8)0;
this->unk310 = (u8)0;
this->unk311 = (u8)0;
```
This is not quite as helpful as you might think: it tells us the size of these variables, but despite mips2c's assertion that they are all unsigned, they may actually be signed: you can't tell from the MIPS unless they are loaded: there is only `sh`, but there are both `lh` and `lhu`, for example. There's not much to choose between them when guessing, but generally signed is a better guess with no other context. For unnamed struct variables, our convention is `unk_30A` etc. Adding them to the struct, we end up with
<details>
<summary>
Large code block, click to show.
</summary>
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ SkelAnime skelAnime;
/* 0x01A8 */ Vec3s jointTable[22];
/* 0x022C */ Vec3s morphTable[22];
/* 0x02B0 */ ColliderCylinder collider;
/* 0x02FC */ char unk_2FC[0x4];
/* 0x0300 */ Actor* childActor;
/* 0x0304 */ char unk_304[0x6];
/* 0x030A */ s16 unk_30A;
/* 0x030C */ char unk_30C[0x2];
/* 0x030E */ s8 unk_30E;
/* 0x030F */ s8 unk_30F;
/* 0x0310 */ s8 unk_310;
/* 0x0311 */ s8 unk_311;
/* 0x0312 */ char unk_312[0x2];
} EnJj; // size = 0x0314
```
We can remove a few more temps that don't look real, and end up with
```C
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
EnJj* this = THIS;
CollisionHeader *sp4C;
// DynaCollisionContext *sp44;
// DynaCollisionContext *temp_a1_2;
// DynaCollisionContext *temp_a1_3;
// char *temp_a1;
s16 temp_v0;
// u32 temp_v0_2;
sp4C = NULL;
Actor_ProcessInitChain(&this->dyna.actor, D_80A88CE0);
ActorShape_Init(&this->dyna.actor.shape, 0.0f, NULL, 0.0f);
temp_v0 = this->dyna.actor.params;
// temp_a1 = this->unk_164;
if (temp_v0 == -1) {
// sp44 = (DynaCollisionContext *) temp_a1;
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
this->unk_30A = 0;
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 0;
this->unk_311 = 0;
if ((*(&gSaveContext + 0xEDA) & 0x400) != 0) {
func_80A87800(this, &func_80A87BEC);
} else {
func_80A87800(this, &func_80A87C30);
}
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
// temp_a1_3 = this + 0x2B0;
// sp44 = temp_a1_3;
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
this->dyna.actor.colChkInfo.mass = 0xFF;
return;
}
if (temp_v0 == 0) {
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
// temp_a1_2 = &globalCtx->colCtx.dyna;
// sp44 = temp_a1_2;
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
this->dyna.actor.update = &func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
return;
}
if (temp_v0 != 1) {
return;
}
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
this->dyna.actor.update = &func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
}
```
</details>
This will still not compile without errors: we need to know what the functions it calls are.
### Functions called
Function pointers do not need `&`, so remove all those. There are three functions that are called in this actor. Firstly, `this->dyna.actor.update = func_80A87F44;` tells us that `func_80A87F44` is an alternative update function for this actor. We therefore give it a prototype similar to the original Update:
```C
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
```
Unfortunately the others are not so easy to deal with. In order to find out what type the functions called by `func_80A87800`, we have to look at `func_80A87800` itself. But fortunately, this is the entire MIPS for `func_80A87800`:
```MIPS
glabel func_80A87800
/* 00000 80A87800 03E00008 */ jr $ra
/* 00004 80A87804 AC8502FC */ sw $a1, 0x02FC($a0) ## 000002FC
```
This is simple enough to read that we don't even need to appeal to mips2c: it saves its second argument into its first argument `+ 0x2FC`. Many actors use this type of function, which we call `SetupAction`: it simply changes the action function.
*Action functions* are the main other kind of function in most actors: they are usually run by Update every frame, and carry out the main actions that the actor does (hence the name). They all have the same arguments, and so we have a typedef for such things: it is
```C
typedef void (*EnJjActionFunc)(struct EnJj*, GlobalContext*);
```
Put this between `struct EnJj;` and the actor struct in the header file. This also gives us another bit of the struct, conveniently plugging the gap at `0x2FC`:
```C
/* 0x02FC */ EnJjActionFunc actionFunc;
```
We have actually learnt three useful pieces of information from this, the other two being that the function above Init is simply
```C
void func_80A87800(EnJj* this, EnJjActionFunc actionFunc) {
this->actionFunc = actionFunc;
}
```
and that `func_80A87BEC` and `func_80A87C30`, passed to it in `EnJj_Init`, are action functions. Since they are first used above where they are defined, we prototype them at the top as well,
```C
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
void func_80A87BEC(EnJj* this, GlobalContext* globalCtx);
void func_80A87C30(EnJj* this, GlobalContext* globalCtx);
```
### Other pointer issues
Mips2c is bad at arrays. We see this in the `(*(&gSaveContext + 0xEDA) & 0x400) != 0`, which will actually stop the compiler working. We need to go and look up what this is actually pointing to, and replace it in the code. Following the trail, we find that:
1. `gSaveContext` is of type `SaveContext`
2. The struct `SaveContext` is defined in `z64save.h`
3. The entry in `SaveContext` that contains `0xEDA` is `/* 0x0ED4 */ u16 eventChkInf[14];`
4. Since `0xEDA - 0xED4 = 0x6`, and `u16`s take up 2 bytes each, we conclude that it is `eventChkInf[3]` that is being referenced.
Therefore, the condition should be `(gSaveContext.eventChkInf[3] & 0x400) != 0`. This is a flag comparison, so we can also leave off the `!= 0`.
With all of this implemented, the function should now compile without errors. The parts of the file that we have changed now look like
<details>
<summary>
Large code block, click to show.
</summary>
```C
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
void func_80A87BEC(EnJj* this, GlobalContext* globalCtx);
void func_80A87C30(EnJj* this, GlobalContext* globalCtx);
/*
const ActorInit En_Jj_InitVars = {
ACTOR_EN_JJ,
ACTORTYPE_ITEMACTION,
FLAGS,
OBJECT_JJ,
sizeof(EnJj),
(ActorFunc)EnJj_Init,
(ActorFunc)EnJj_Destroy,
(ActorFunc)EnJj_Update,
(ActorFunc)EnJj_Draw,
};
*/
extern ColliderCylinderInit D_80A88CB4;
// static ColliderCylinderInit sCylinderInit = {
// {
// COLTYPE_NONE,
// AT_NONE,
// AC_ON | AC_TYPE_PLAYER,
// OC1_ON | OC1_TYPE_ALL,
// OC2_TYPE_1,
// COLSHAPE_CYLINDER,
// },
// {
// ELEMTYPE_UNK0,
// { 0x00000000, 0x00, 0x00 },
// { 0x00000004, 0x00, 0x00 },
// TOUCH_NONE,
// BUMP_ON,
// OCELEM_ON,
// },
// { 170, 150, 0, { 0, 0, 0 } },
// };
extern InitChainEntry D_80A88CE0[];
// static InitChainEntry sInitChain[] = {
// ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
// };
// glabel D_80A88CF0
// .word 0xC4C6A000, 0x42540000, 0xC22C0000
// glabel D_80A88CFC
// .word 0x06007698, 0x06007A98, 0x06007E98, 0x00000000, 0x00000000
extern UNK_TYPE D_06000A1C;
extern UNK_TYPE D_06001830;
extern AnimationHeader D_06001F4C;
extern FlexSkeletonHeader D_0600B9A8;
extern UNK_TYPE D_0600BA8C;
// #pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/func_80A87800.s")
void func_80A87800(EnJj* this, EnJjActionFunc actionFunc) {
this->actionFunc = actionFunc;
}
// #pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/EnJj_Init.s")
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
EnJj* this = THIS;
CollisionHeader *sp4C;
// DynaCollisionContext *sp44;
// DynaCollisionContext *temp_a1_2;
// DynaCollisionContext *temp_a1_3;
// char *temp_a1;
s16 temp_v0;
// u32 temp_v0_2;
sp4C = NULL;
Actor_ProcessInitChain(&this->dyna.actor, D_80A88CE0);
ActorShape_Init(&this->dyna.actor.shape, 0.0f, NULL, 0.0f);
temp_v0 = this->dyna.actor.params;
// temp_a1 = this->unk_164;
if (temp_v0 == -1) {
// sp44 = (DynaCollisionContext *) temp_a1;
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
this->unk_30A = 0;
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 0;
this->unk_311 = 0;
if ((gSaveContext.eventChkInf[3] & 0x400) != 0) {
func_80A87800(this, func_80A87BEC);
} else {
func_80A87800(this, func_80A87C30);
}
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
// temp_a1_3 = this + 0x2B0;
// sp44 = temp_a1_3;
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
this->dyna.actor.colChkInfo.mass = 0xFF;
return;
}
if (temp_v0 == 0) {
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
// temp_a1_2 = &globalCtx->colCtx.dyna;
// sp44 = temp_a1_2;
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
this->dyna.actor.update = func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
return;
}
if (temp_v0 != 1) {
return;
}
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
this->dyna.actor.update = func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
}
```
</details>
## Diff
Once preliminary cleanup and struct filling is done, most time spent matching functions is done by comparing the original code with the code you have compiled. This is aided by a program called `diff.py`.
In order to use `diff.py` with the symbol names, we need a copy of the code to compare against. This is done by copying the `build` directory into a directory called `expected`. Copying in Windows on WSL is very slow, so run
```
$ mkdir expected
cp -r build/ expected/
```
from the main directory of the repository. You should end up with the directory structure `expected/build/...`.
You may want to do this again when you start renaming functions. *Make sure that you copy an OK build, or you are going to get very confused.* You should also do this again after needing to do a `make clean`.
Now, we run diff on the function name: in the main directory,
```
$ ./diff.py -mwo3 EnJj_Init
```
(To see what these arguments do, run it with `./diff.py -h` or look in the scripts documentation.)
This gives the following:
<details>
<summary>
Large image, click to show.
</summary>
![Init diff 1](images/init_diff1.png)
</details>
The code we want is on the left, current code on the right. To spot where the function ends, either look for where stuff is added and subtracted from the stack pointer in successive lines, or for a
```MIPS
jr ra
nop
```
The colours mean the following:
- White/gray is matching lines
- Red is lines missing
- Green is extra lines
- Blue denotes significant differences in instructions, be they just numerical ones, or whole instructions
- Yellow/Gold denotes that instructions are correct but register usage is wrong
- Other colors are used to distinguish incorrectly used registers or stack variables, to make it easy to follow where they are used.
- The colored arrows denote branching. An arrow of one color on the right leads to the arrow of the same color on the left.
Obviously we want to make the whole thing white. This is the tricky bit: you have to have the imagination to try different things until you get the diff to match. You learn these with experience.
Generally, the order of what to fix should be:
1. Control flow (conditionals, where branches go)
2. Instruction ordering and type (functions cannot change order, which is a useful indicator)
3. Regalloc (register allocation) differences
4. Stack differences
(It is this order because the things that happen earlier can influence the things that happen later.)
You can keep the diff open in the terminal, and it will refresh when the C file (but not the H file) is changed with these settings.
In this case, we see that various branches are happening in the wrong place. Here I fear experience is necessary: notice that the function has three blocks that look quite similar, and three separate conditionals that depend on the same variable. This is a good indicator of a switch. Changing the function to use a switch,
```C
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx) {
EnJj* this = THIS;
s32 sp4C;
s16 temp_v0;
sp4C = 0;
Actor_ProcessInitChain(&this->dyna.actor, D_80A88CE0);
ActorShape_Init(&this->dyna.actor.shape, 0.0f, NULL, 0.0f);
temp_v0 = this->dyna.actor.params;
switch (temp_v0) {
case -1:
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable,
this->morphTable, 22);
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
this->unk_30A = 0;
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 0;
this->unk_311 = 0;
if ((gSaveContext.eventChkInf[3] & 0x400) != 0) {
func_80A87800(this, func_80A87BEC);
} else {
func_80A87800(this, func_80A87C30);
}
this->childActor = Actor_SpawnAsChild(
&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f,
this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
this->dyna.bgId =
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
this->dyna.actor.colChkInfo.mass = 0xFF;
break;
case 0:
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
// temp_a1_2 = &globalCtx->colCtx.dyna;
// sp44 = temp_a1_2;
this->dyna.bgId =
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
this->dyna.actor.update = func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
break;
case 1:
DynaPolyActor_Init(&this->dyna, 0);
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
this->dyna.bgId =
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
this->dyna.actor.update = func_80A87F44;
this->dyna.actor.draw = NULL;
Actor_SetScale(&this->dyna.actor, 0.087f);
break;
}
}
```
we see that the diff is nearly correct (note that `-3` lets you compare current with previous):
<details>
<summary>
Large image, click to show.
</summary>
![Init diff 2](images/init_diff2.png)
</details>
except we still have some stack issues. Now that `temp_v0` is only used once, it looks fake. Eliminating it actually seems to make the stack worse. To fix this, we employ something that we have evidence that the developers did: namely, we make a copy of `globalCtx` (the theory is that they actually used `gameState` as an argument of the main 4 functions, just like we used `Actor* thisx` as the first argument.) The quick way to do this is to change the top of the function to
```C
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
EnJj* this = THIS;
...
```
It turns out that this is enough to completely fix the diff:
![Init diff 2](images/init_diff3top.png)
(last two edits, only top shown for brevity)
Everything *looks* fine, but we only know for sure when we run `make`. Thankfully doing so gives
```
zelda_ocarina_mq_dbg.z64: OK
```
which is either a sense of triumph or relief depending on how long you've spent on a function.
And with that, we have successfully matched our first function. (Or first two counting `func_80A87800`)
**N.B** Notice that we don't yet have much idea of what this code actually does: this should be clarified by going through the rest of the actor's functions, which is discussed in the next document.
Next: [Other functions in the actor](other_functions.md)

View File

@ -1,62 +0,0 @@
# Getting started
## [Introduction to decomp](introduction.md)
- What we are doing
- Structure of the code
## Pre-decompilation
- Building the repo (follow the instructions in the README.md)
- Most of us use VSCode. (You can watch Fig's video to get an idea of how this can be used). Some useful information is [here](vscode.md).
- Choosing a first actor (You want something small that has simple interactions with the environment. But OoT is far enough in that there are basically no unreserved actors left anyway now.)
## Decompilation
- [Begining decompilation: order, Init and the actor struct](beginning_decomp.md)
- Order of decompilation
- Init and common actor features
- Initchains
- Actors and dynapoly actors
- Colliders
- Skelanime
- Matching
- Using diff
- control flow (branches) -> instruction ordering -> register allocation -> stack
- [The rest of the functions in the actor](other_functions.md)
- Order of decompilation
- Action Functions and other functions
- More on matching: the permuter
- [Draw functions](draw_functions.md)
- [Data, migration and non-migration](data.md)
- Importing the data: early and late
- Fake symbols
- Inlining
## [Object Decompilation](object_decomp.md)
- Object files
- How we decompile objects
- [Example](object_decomp_example.md)
## After Decompilation
- [Preparing to merge](merging.md)
- Preliminary documentation
- Preparing to PR
- Pull Requests
- Trello
## Appendices
- [Types, Structs and Padding](types_structs_padding.md) (a miscellany of useful stuff)
- [Helper scripts](helper_scripts.md)
To be written, maybe
- How we use git and GitHub
- Some notes on the basic structure of N64 MIPS
- Glossary
- Conventions

View File

@ -1,648 +0,0 @@
# Data
## Table of Contents
- [Data first](#data-first)
* [Example: `EnTg`](#example-entg)
- [Extern and data last](#extern-and-data-last)
- [Fake symbols](#fake-symbols)
- [Inlining](#inlining)
Each actor's data is stored in a separate file. EnJj's data is in `data/overlays/actors/z_en_jj.data.s`, for example. At some point in the decompilation process we need to convert this raw data into recognisable information for the C to use.
There are two main ways to do this: either
1. import the data first and type it later, or
2. wait until the data appears in functions, extern it, then import it at the end
Sometimes something between these two is appropriate: wait until the largest or strangest bits of data appear in functions, get some typing information out of that, and then import it, but for now, let's stick to both of these.
Both approaches have their advantages and disadvantages.
## Data first
<!-- Fig shows how to do this in his video. -->
This way is good for smaller actors with little data. It is not really suitable for EnJj, for example, because of the enormous section of data labelled as `D_80A88164`.
### Example: `EnTg`
We give a simple example of this approach with a small NPC actor, EnTg, that is, the spinning couple.
The data file looks like
<details>
<summary>
Large code block, click to show
</summary>
```
.include "macro.inc"
# assembler directives
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
.set gp=64 # allow use of 64-bit general purpose registers
.section .data
.balign 16
glabel D_80B18910
.word 0x0A000039, 0x20010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00140040, 0x00000000, 0x00000000
glabel D_80B1893C
.word 0x00000000, 0x00000000, 0xFF000000
glabel En_Tg_InitVars
.word 0x01AC0400, 0x00000009, 0x01820000, 0x0000020C
.word EnTg_Init
.word EnTg_Destroy
.word EnTg_Update
.word EnTg_Draw
glabel D_80B18968
.word 0x00000000, 0x44480000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
```
</details>
We transfer this data into the actor file by pretending it is an array of words. The InitVars have already been processed and inserted into the C file, so just need to be uncommented. Data cannot change order, so the two pieces above the InitVars must stay there. At the end of this process, the top of the file will look like
<details>
<summary>
Large code block, click to show
</summary>
```C
/*
* File: z_en_tg.c
* Overlay: ovl_En_Tg
* Description: Honey & Darling
*/
#include "z_en_tg.h"
#define FLAGS 0x00000009
#define THIS ((EnTg*)thisx)
void EnTg_Init(Actor* thisx, GlobalContext* globalCtx);
void EnTg_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnTg_Update(Actor* thisx, GlobalContext* globalCtx);
void EnTg_Draw(Actor* thisx, GlobalContext* globalCtx);
s32 D_80B18910[] = { 0x0A000039, 0x20010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00140040, 0x00000000, 0x00000000 };
s32 D_80B1893C[] = { 0x00000000, 0x00000000, 0xFF000000 };
const ActorInit En_Tg_InitVars = {
ACTOR_EN_TG,
ACTORTYPE_NPC,
FLAGS,
OBJECT_MU,
sizeof(EnTg),
(ActorFunc)EnTg_Init,
(ActorFunc)EnTg_Destroy,
(ActorFunc)EnTg_Update,
(ActorFunc)EnTg_Draw,
};
s32 D_80B18968[] = { 0x00000000, 0x44480000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
extern UNK_TYPE D_06005040;
extern UNK_TYPE D_0600AE40;
```
</details>
Now, open the file called `spec` in the base directory, find the section corresponding to EnTg:
```
beginseg
name "ovl_En_Tg"
include "build/src/overlays/actors/ovl_En_Tg/z_en_tg.o"
include "build/data/overlays/actors/z_en_tg.data.o"
include "build/data/overlays/actors/z_en_tg.reloc.o"
endseg
```
and comment out the .data line,
```
beginseg
name "ovl_En_Tg"
include "build/src/overlays/actors/ovl_En_Tg/z_en_tg.o"
//include "build/data/overlays/actors/z_en_tg.data.o"
include "build/data/overlays/actors/z_en_tg.reloc.o"
endseg
```
to tell the compiler not to look for the data in that file any more. Now run `make -j`, and if you did both steps correctly, you should get `OK`.
Now carry out the usual steps to decompile `Init`. The usual cleanup and struct population gets us to
```C
void EnTg_Init(Actor *thisx, GlobalContext *globalCtx) {
EnTg *this = THIS;
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawFunc_Circle, 28.0f);
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600AE40, &D_06005040, 0, 0, 0);
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, (ColliderCylinderInit *) D_80B18910);
func_80061EFC(&this->actor.colChkInfo, NULL, (CollisionCheckInfoInit2 *) D_80B1893C);
this->actor.unk_1F = 6;
Actor_SetScale(&this->actor, 0.01f);
this->actionFunc = func_80B185C0;
this->unk_208 = globalCtx->state.frames & 1;
}
```
and it remains to deal with the data. mips2c has told us what the types should be. We run `colliderinit` on `D_80B18910` as usual, which gives
```
$ ./tools/overlayhelpers/colliderinit.py 80B18910 ColliderCylinderInit
ovl_En_Tg: Rom 00ECE1F0:00ECE910 VRam 80B18360:80B18A80 Offset 0005B0
static ColliderCylinderInit sCylinderInit =
{
{ COLTYPE_UNK10, 0x00, 0x00, 0x39, 0x20, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, 0x00, 0x00, 0x01 },
{ 20, 64, 0, { 0, 0, 0 } },
};
```
Copy this in below `D_80B18910`, delete the original words of data, change the name back to `D_80B18910`, and put `sCylinderInit` commented out above it:
```C
// sCylinderInit
static ColliderCylinderInit D_80B18910 =
{
{ COLTYPE_UNK10, 0x00, 0x00, 0x39, 0x20, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, 0x00, 0x00, 0x01 },
{ 20, 64, 0, { 0, 0, 0 } },
};
```
For the `CollisionCheckInfoInit2`, we don't have a script to separate it, but you can look in other files to see that it should be separated as
```C
// sColChkInit
CollisionCheckInfoInit2 D_80B1893C = { 0, 0, 0, 0, 0xFF };
```
One more thing needs to change: since both are no longer arrays, we need to make the uses in the functions pointers:
```C
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &D_80B18910);
func_80061EFC(&this->actor.colChkInfo, NULL, &D_80B1893C);
```
A quick check of the diff shows that we just need to put the action function set to last, and it matches.
Following the function tree as usual, we find the only other place any data is used is in `func_80B1871C`. From its use in `EnTg_Draw`, we realise that this is a `PostLimbDraw` function. Giving mips2c the correct prototype, it comes out as
```C
void func_80B1871C(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
? sp18;
sp18.unk0 = (s32) D_80B18968->unk0;
sp18.unk4 = (s32) D_80B18968[1];
sp18.unk8 = (s32) D_80B18968[2];
if (limbIndex == 9) {
Matrix_MultVec3f((Vec3f *) &sp18, thisx + 0x38);
}
}
```
which clearly doesn't like the words we fed it. We see that `sp18` should be a `Vec3f` from the cast in the `Matrix_MultVec3f`, so the last three words are padding (a `Vec3f` has size `0xC`, and it's not using it like an array), and we can convert it to
```C
Vec3f D_80B18968 = { 0.0f, 800.0f, 0.0f };
```
and the function matches as
```C
void func_80B1871C(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
EnTg* this = THIS;
Vec3f sp18 = D_80B18968;
if (limbIndex == 9) {
Matrix_MultVec3f(&sp18, &this->actor.world2.pos);
}
}
```
(we can see from the assembly doing `lw` and `sw` rather than `lwc1` and `swc1` that it is doing a struct copy, rather than setting it componentwise).
## Extern and data last
Externing is explained in detail in the document about the [Init function](beginning_decomp.md). To summarize, every time a `D_address` appears that is in the data file, we put a
```C
extern UNK_TYPE D_address;
```
at the top of the file, in the same order that the data appears in the data file. We can also give it a type if we know what the type actually is (e.g. for colliders, initchains, etc.), and convert the actual data and place it commented-out under the corresponding line. This means we don't have to do everything at once at the end.
Once we have decompiled enough things to know what the data is, we can import it. The advantage of doing it this way is we should know what type everything is already: in our work on EnJj, for example, we ended up with the following data at the top of the file
```C
extern UNK_TYPE D_80A88164;
extern ColliderCylinderInit D_80A88CB4;
// static ColliderCylinderInit sCylinderInit =
// {
// { COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
// { 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
// { 170, 150, 0, { 0, 0, 0 } },
// };
extern InitChainEntry D_80A88CE0[];
// static InitChainEntry sInitChain[] = {
// ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
// ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
// };
extern Vec3f D_80A88CF0;
// static Vec3f D_80A88CF0 = { -1589.0f, 53.0f, -43.0f };
extern Gfx* D_80A88CFC[];
// static Gfx* D_80A88CFC[] = { 0x06007698, 0x06007A98, 0x06007E98, }
```
and the only thing we don't know about is the cutscene data `D_80A88164`.
*Before doing anything else, make sure `make` gives `OK`.*
First, we tell the compiler to ignore the original data file. To do this, open the file called `spec` in the main directory of the repository, and search for the actor name. You will find a section that looks like
```
beginseg
name "ovl_En_Jj"
include "build/src/overlays/actors/ovl_En_Jj/z_en_jj.o"
include "build/data/overlays/actors/z_en_jj.data.o"
include "build/data/overlays/actors/z_en_jj.reloc.o"
endseg
```
We will eventually remove both of the bottom two lines and replace them with our own reloc file, but for now, just comment out the data line:
```
beginseg
name "ovl_En_Jj"
include "build/src/overlays/actors/ovl_En_Jj/z_en_jj.o"
//include "build/data/overlays/actors/z_en_jj.data.o"
include "build/data/overlays/actors/z_en_jj.reloc.o"
endseg
```
Next remove all the externs, and uncomment their corresponding commented data:
```C
extern UNK_TYPE D_80A88164;
static ColliderCylinderInit sCylinderInit =
{
{ COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
{ 170, 150, 0, { 0, 0, 0 } },
};
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
};
static Vec3f D_80A88CF0 = { -1589.0f, 53.0f, -43.0f };
static Gfx* D_80A88CFC[] = { 0x06007698, 0x06007A98, 0x06007E98, }
```
Find-and-replace `D_80A88CB4` and `D_80A88CE0` by `sCylinderInit` and `sInitChain` respectively. Notice the naming scheme: static data symbols always start with `s` in our style. (Unless they are inlined, but we'll worry about that later.)
We still need to deal with the cutscene data. This is special: because it's so large, it goes in its own file. Make a new file called `z_en_jj_cutscene_data.c` in the same directory as `z_en_jj.c`. Include the actor's header file and `z64cutscene_commands.h`, and put `// clang-format off` and `// clang-format on` in the file (this is so that our formatting script doesn't wreak havoc with the formatting of the cutscene macros). Thus the contents of the file is currently
```C
#include "z_en_jj.h"
#include "z64cutscene_commands.h"
// clang-format off
// clang-format on
```
Finally, we have a script to convert the cutscene data into macros, namely `csdis.py` in the tools folder. We can just give it the VRAM address that the `D_address` is referring to, and it will output the cs macros:
<details>
<summary>
(Very) long code block, click to view
</summary>
```
$ ./tools/csdis.py 80A88164
ovl_En_Jj: Rom 00E3E3D0:00E3F9E0 VRam 80A87800:80A88E10 Offset 000964
static CutsceneData D_80A88164[] = {
CS_BEGIN_CUTSCENE(26, 1629),
CS_PLAYER_ACTION_LIST(4),
CS_PLAYER_ACTION(0x0005, 0, 240, 0x0000, 0x4000, 0x0000, -1732, 52, -44, -1732, 52, -44, 1.1393037197548209e-29f, 0.0f, 1.401298464324817e-45f),
CS_PLAYER_ACTION(0x0003, 240, 255, 0x0000, 0x4000, 0x0000, -1732, 52, -44, -1732, 52, -44, 1.1393037197548209e-29f, 0.0f, 1.401298464324817e-45f),
CS_PLAYER_ACTION(0x0006, 255, 285, 0x0000, 0x4000, 0x0000, -1732, 52, -44, -1732, 52, -44, 1.1393037197548209e-29f, 0.0f, 1.401298464324817e-45f),
CS_PLAYER_ACTION(0x0020, 285, 300, 0x0000, 0xC000, 0x0000, -1732, 52, -44, -1537, 109, -44, 1.1393037197548209e-29f, 0.0f, 1.401298464324817e-45f),
CS_NPC_ACTION_LIST(68, 4),
CS_NPC_ACTION(0x0001, 0, 234, 0x0000, 0x4000, 0x0000, -1665, 52, -44, -1665, 52, -44, 1.1393037197548209e-29f, 0.0f, 1.401298464324817e-45f),
CS_NPC_ACTION(0x0002, 234, 241, 0x41F8, 0x0000, 0x0000, -1665, 52, -44, -1603, 130, -47, 8.857142448425293f, 11.142857551574707f, -8.857142448425293f),
CS_NPC_ACTION(0x0002, 241, 280, 0x4031, 0x0000, 0x0000, -1603, 130, -47, -549, 130, -52, 27.0256404876709f, 0.0f, -27.0256404876709f),
CS_NPC_ACTION(0x0003, 280, 300, 0x0000, 0x0000, 0x0000, -549, 130, -52, -549, 130, -52, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION_LIST(67, 5),
CS_NPC_ACTION(0x0001, 0, 93, 0x0000, 0x0000, 0x0000, 0, 51, 124, 0, 51, 124, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION(0x0003, 93, 121, 0x0000, 0x0000, 0x0000, 0, 51, 124, 0, 51, 124, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION(0x0001, 121, 146, 0x0000, 0x0000, 0x0000, 0, 51, 124, 0, 51, 124, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION(0x0002, 146, 241, 0x0000, 0x0000, 0x0000, 0, 51, 124, 0, 51, 124, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION(0x0001, 241, 441, 0x0000, 0x0000, 0x0000, 0, 51, 124, 0, 51, 124, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION_LIST(69, 3),
CS_NPC_ACTION(0x0001, 0, 90, 0x0000, 0x0000, 0x0000, 0, -33, 9, 0, -33, 9, 0.0f, 0.0f, 0.0f),
CS_NPC_ACTION(0x0002, 90, 330, 0x0000, 0x0000, 0x0000, 0, -33, 9, 0, -62, 22, 0.0f, -0.12083332985639572f, 0.0f),
CS_NPC_ACTION(0x0003, 330, 380, 0x0000, 0x0000, 0x0000, 0, -62, 22, 0, -62, 22, 0.0f, 0.0f, 0.0f),
CS_MISC_LIST(1),
CS_MISC(0x000C, 1095, 1161, 0x0000, 0x00000000, 0xFFFFFFD2, 0x00000000, 0xFFFFFFD0, 0xFFFFFFD2, 0x00000000, 0xFFFFFFD0, 0x00000000, 0x00000000, 0x00000000),
CS_SCENE_TRANS_FX(0x0009, 0, 10),
CS_PLAYER_ACTION_LIST(1),
CS_PLAYER_ACTION(0x0035, 300, 1629, 0x0000, 0x0000, 0x0000, -1630, 52, -52, -1630, 52, -52, 0.0f, 0.0f, 0.0f),
CS_CAM_EYE_LIST(0, 1091),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x015C),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x016D),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x017E),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x0223),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x7065),
CS_CAM_EYE_LIST(60, 1151),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1532, 251, 222, 0x015C),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1532, 251, 222, 0x016D),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1532, 251, 222, 0x017E),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1532, 251, 222, 0x0223),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.39994430541992f, -1532, 251, 222, 0x7065),
CS_CAM_EYE_LIST(90, 351),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1698, 382, 455, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1698, 382, 455, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1698, 382, 455, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1694, 380, 451, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 32.99989700317383f, -1694, 380, 451, 0xAC10),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 32.99989700317383f, -1694, 380, 451, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 32.99989700317383f, -1694, 380, 451, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 32.99989700317383f, -1694, 380, 451, 0x0164),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 32.99989700317383f, -1694, 380, 451, 0xAD78),
CS_CAM_EYE_LIST(220, 392),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0xAC10),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x0000),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.39994430541992f, -1641, 95, -41, 0x0000),
CS_CAM_EYE_LIST(240, 1331),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1810, 65, -15, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1810, 65, -15, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1810, 65, -15, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1810, 65, -15, 0x0000),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.599945068359375f, -1810, 65, -15, 0xAC10),
CS_CAM_EYE_LIST(280, 1371),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1531, 95, -7, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1531, 95, -7, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1531, 95, -7, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.599945068359375f, -1531, 95, -7, 0x0000),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.599945068359375f, -1531, 95, -7, 0xAC10),
CS_CAM_EYE_LIST(310, 1421),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1717, 83, -59, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1717, 83, -59, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1649, 177, -59, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1533, 224, -59, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -1243, 180, -59, 0xAC10),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -953, 71, -55, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -953, 71, -55, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 45.39994430541992f, -953, 71, -55, 0x0164),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 45.39994430541992f, -953, 71, -55, 0xAD78),
CS_CAM_EYE_LIST(355, 1466),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0xAC34),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0x4428),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0x0000),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0xAC10),
CS_CAM_EYE(CS_CMD_CONTINUE, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0x0000),
CS_CAM_EYE(CS_CMD_STOP, 0x00, 0, 60.60000228881836f, -1830, 103, 18, 0x0000),
CS_CAM_AT_LIST(0, 1120),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1724, -5, -45, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1724, -5, -45, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 45.39994430541992f, -1724, -5, -45, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1724, -5, -45, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.39994430541992f, -1724, -5, -45, 0xAC10),
CS_CAM_AT_LIST(60, 1180),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1440, 241, 134, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1440, 241, 134, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 45.39994430541992f, -1440, 241, 134, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1440, 241, 134, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.39994430541992f, -1440, 241, 134, 0xAC10),
CS_CAM_AT_LIST(90, 380),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1610, 348, 373, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1610, 348, 373, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 50, 45.39994430541992f, -1610, 348, 373, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 35.399906158447266f, -1614, 338, 367, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 32.99989700317383f, -1614, 338, 367, 0xAC10),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 32.99989700317383f, -1614, 338, 367, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 32.99989700317383f, -1614, 338, 367, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 32.99989700317383f, -1614, 338, 367, 0x0164),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 32.99989700317383f, -1614, 338, 367, 0xAD78),
CS_CAM_AT_LIST(220, 421),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1724, -5, -45, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 70, 45.39994430541992f, -1724, -5, -45, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 5, 45.39994430541992f, -1724, -5, -45, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 6, 45.79994583129883f, -1593, 150, -146, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1531, 152, -75, 0xAC10),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -1531, 152, -75, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.39994430541992f, -1531, 152, -75, 0x0000),
CS_CAM_AT_LIST(240, 1360),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1712, 74, -37, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1712, 74, -37, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 45.599945068359375f, -1712, 74, -37, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1712, 74, -37, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.599945068359375f, -1712, 74, -37, 0xAC10),
CS_CAM_AT_LIST(280, 1400),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1619, 99, -50, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1619, 99, -50, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 45.599945068359375f, -1619, 99, -50, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.599945068359375f, -1619, 99, -50, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.599945068359375f, -1619, 99, -50, 0xAC10),
CS_CAM_AT_LIST(310, 1450),
CS_CAM_AT(CS_CMD_CONTINUE, 0x0B, 30, 90.99960327148438f, -1610, 141, -59, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x09, 10, 90.79960632324219f, -1599, 114, -57, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0xFC, 10, 90.39961242675781f, -1528, 192, -54, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 10, 90.599609375f, -1427, 164, -54, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0xCB, 10, 90.39961242675781f, -1138, 119, -37, 0xAC10),
CS_CAM_AT(CS_CMD_CONTINUE, 0x20, 10, 90.39961242675781f, -832, 50, -51, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 45.39994430541992f, -836, 35, -51, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 45.39994430541992f, -836, 35, -51, 0x0164),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 45.39994430541992f, -836, 35, -51, 0xAD78),
CS_CAM_AT_LIST(355, 1495),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 60.60000228881836f, -1706, 111, -6, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 60.60000228881836f, -1706, 111, -6, 0xAC34),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 10, 60.60000228881836f, -1706, 111, -6, 0x4428),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 10, 60.60000228881836f, -1721, 82, -42, 0x0000),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 1000, 60.60000228881836f, -1721, 82, -42, 0xAC10),
CS_CAM_AT(CS_CMD_CONTINUE, 0x00, 30, 60.60000228881836f, -1721, 82, -42, 0x0000),
CS_CAM_AT(CS_CMD_STOP, 0x00, 30, 60.60000228881836f, -1721, 82, -42, 0x0000),
CS_SCENE_TRANS_FX(0x000B, 335, 342),
CS_TERMINATOR(JABU_JABU_INTRO, 345, 395),
CS_NPC_ACTION_LIST(62, 1),
CS_NPC_ACTION(0x0001, 305, 494, 0x0000, 0x0000, 0x0000, -1399, 452, -53, -1399, 452, -53, 0.0f, 0.0f, 0.0f),
CS_END(),
};
```
</details>
Copy this into the file we just made (given the length, you may prefer to `>` it into a file and copy it from there, rather than the terminal itself). Save and close that file: we won't need it any more.
To replace the `extern`, because the data is in a separate file, we include the file in a particular way:
```C
#include "z_en_jj_cutscene_data.c" EARLY
```
(`EARLY` is required specifically for cutscene data. See [the definition of the CutsceneData struct](../include/z64cutscene.h) for exactly why.)
Lastly, uncomment the InitVars block that's been sitting there the whole time. The data section of the file now looks like
```C
const ActorInit En_Jj_InitVars = {
ACTOR_EN_JJ,
ACTORTYPE_ITEMACTION,
FLAGS,
OBJECT_JJ,
sizeof(EnJj),
(ActorFunc)EnJj_Init,
(ActorFunc)EnJj_Destroy,
(ActorFunc)EnJj_Update,
(ActorFunc)EnJj_Draw,
};
#include "en_jj_cutscene_data.c" EARLY
static ColliderCylinderInit sCylinderInit =
{
{ COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
{ 170, 150, 0, { 0, 0, 0 } },
};
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_STOP),
};
static Vec3f D_80A88CF0 = { -1589.0f, 53.0f, -43.0f };
static Gfx* D_80A88CFC[] = { 0x06007698, 0x06007A98, 0x06007E98, };
```
That should be everything, and we should now be able to `make` without the data file with no issues
But running `make`, we get the dreaded Error 1:
```
md5sum: WARNING: 1 computed checksum did NOT match
make: *** [Makefile:172: all] Error 1
```
Oh no! What went wrong?
To find out what went wrong, we need to use `firstdiff.py`. This tells us where our ROM starts to differ:
```
$ ./firstdiff.py
First difference at ROM addr 0x144F4, gDmaDataTable (RAM 0x80016DA0, ROM 0x12F70, build/asm/dmadata.o)
Bytes: 00:E3:F9:D0 vs 00:E3:F9:E0
Instruction difference at ROM addr 0xE3ED48, En_Jj_InitVars (RAM 0x80A88140, ROM 0xE3ED10, build/src/overlays/actors/ovl_En_Jj/z_en_jj.o)
Bytes: 40:00:00:00 vs 00:F0:00:00
Instruction difference at ROM addr 0xE3F900, D_80A88D40 (RAM 0x80A88D30, ROM 0xE3F900, build/data/overlays/actors/z_en_jj.reloc.o)
Bytes: 00:00:09:40 vs C4:89:80:00
Instruction difference at ROM addr 0xE3F9D4, En_Js_SetupAction (RAM 0x80A88E00, ROM 0xE3F9D0, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: AC:85:02:8C vs 00:00:00:00
Instruction difference at ROM addr 0xE3F9D8, EnJs_Init (RAM 0x80A88E08, ROM 0xE3F9D8, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: 27:BD:FF:B0 vs 00:00:00:00
Instruction difference at ROM addr 0xE3FAFC, EnJs_Destroy (RAM 0x80A88F2C, ROM 0xE3FAFC, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: 27:BD:FF:E8 vs 8F:B0:00:34
Over 1000 differing words, must be a shifted ROM.
Map appears to have shifted just before D_80A88D40 (build/data/overlays/actors/z_en_jj.reloc.o) -- in En_Jj_InitVars?
```
Ignore the first line: `gDmaDataTable` is always different if the ROM is shifted. The useful lines are usually the next line, and the guess it makes at the end.
To fix this, we use a binary diff program. A suitable one is `vbindiff`: run it on the baserom and the zelda_whatever one the compiler generates:
```
vbindiff baserom.z64 zelda_ocarina_mq_dbg.z64
```
In this, press `g` to open up goto position, and paste in the address `0xE3ED10` from the first important line of the `first_diff` output. This gives us the following:
![vbindiff for data](images/vbindiff_data_1.png)
Notice that the numbers in the bottom pane is all shifted one word to the left. We therefore need some extra padding somewhere. The real issue is where. Thankfully the guess at the bottom gives us a hint: let's try just under `InitVars`. Just put a padding variable straight after them:
```C
const ActorInit En_Jj_InitVars = {
ACTOR_EN_JJ,
ACTORTYPE_ITEMACTION,
FLAGS,
OBJECT_JJ,
sizeof(EnJj),
(ActorFunc)EnJj_Init,
(ActorFunc)EnJj_Destroy,
(ActorFunc)EnJj_Update,
(ActorFunc)EnJj_Draw,
};
s32 usused = 0;
#include "z_en_jj_cutscene_data.c" EARLY
```
This isn't good enough: we still get Error 1, but:
```
$ ./first_diff.py
First difference at ROM addr 0x144F4, gDmaDataTable (RAM 0x80016DA0, ROM 0x12F70, build/asm/dmadata.o)
Bytes: 00:E3:F9:D0 vs 00:E3:F9:E0
Instruction difference at ROM addr 0xE3F87C, unused (RAM 0x80A88160, ROM 0xE3ED30, build/src/overlays/actors/ovl_En_Jj/z_en_jj.o)
Bytes: 0A:00:09:39 vs 00:00:00:00
Instruction difference at ROM addr 0xE3F900, D_80A88D40 (RAM 0x80A88D30, ROM 0xE3F900, build/data/overlays/actors/z_en_jj.reloc.o)
Bytes: 00:00:09:40 vs C4:89:80:00
Instruction difference at ROM addr 0xE3F9D4, En_Js_SetupAction (RAM 0x80A88E00, ROM 0xE3F9D0, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: AC:85:02:8C vs 00:00:00:00
Instruction difference at ROM addr 0xE3F9D8, EnJs_Init (RAM 0x80A88E08, ROM 0xE3F9D8, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: 27:BD:FF:B0 vs 00:00:00:00
Instruction difference at ROM addr 0xE3FAFC, EnJs_Destroy (RAM 0x80A88F2C, ROM 0xE3FAFC, build/src/overlays/actors/ovl_En_Js/z_en_js.o)
Bytes: 27:BD:FF:E8 vs 8F:B0:00:34
Over 1000 differing words, must be a shifted ROM.
Map appears to have shifted just before D_80A88D40 (build/data/overlays/actors/z_en_jj.reloc.o) -- in unused?
(Base map file expected/build/z64.map out of date due to new or renamed symbols, so result may be imprecise.)
```
We've managed to get rid of one issue, but there's still another one. Looking in vbindiff again,
![vbindiff data 2](images/vbindiff_data_2.png)
we see that everything is shifted left by 2 words. Guessing based on the hint from `first_diff`, we put two words after the cutscene include:
```C
#include "z_en_jj_cutscene_data.c" EARLY
s32 usused2[] = { 0, 0 };
static ColliderCylinderInit sCylinderInit =
{
{ COLTYPE_UNK10, 0x00, 0x09, 0x39, 0x10, COLSHAPE_CYLINDER },
{ 0x00, { 0x00000000, 0x00, 0x00 }, { 0x00000004, 0x00, 0x00 }, 0x00, 0x01, 0x01 },
{ 170, 150, 0, { 0, 0, 0 } },
};
```
Running `make -j` again,
```
zelda_ocarina_mq_dbg.z64: OK
```
Hooray, we won!
## Fake symbols
Some symbols in the data have been decompiled wrongly, being incorrectly separated from the previous symbol due to how it was accessed by the actor's functions. However, most of these have now been fixed. Some more detail is given in [Types, structs and padding](types_structs_padding.md) If you are unsure, ask!
## Inlining
After the file is finished, it is possible to move some static data into functions. This requires that:
1. The data is used in only one function
2. The ordering of the data can be maintained
Additionally, we prefer to keep larger data (more than a line or two) out of functions anyway.
# Finally: .bss
A .bss contains data that is uninitialised (actually initialised to `0`). For most actors all you need to do is declare it at the top of the actor file without giving it a value, once you find out what type it is.

View File

@ -1,475 +0,0 @@
# Draw functions
Up: [Contents](contents.md)
Previous: [The rest of the functions in the actor](other_functions.md)
Draw functions behave completely differently from the other functions in an actor. They often use a lot of macros.
For this tutorial we will first look at the `EnJj` draw function, `EnJj_Draw`, then some more complicated examples.
## A first example
Unless it is completely invisible, an actor usually has a draw function as one of the main four actor functions. Hence its prototype looks like
```C
EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
```
As in Init, Destroy and Update, it is much more convenient to feed mips2c the fake prototype
```C
EnJj_Draw(EnJj* this, GlobalContext* globalCtx);
```
so that it fills out the struct fields from the actuar actor; we then put a
```C
EnJj* this = THIS;
```
in the declarations as before. From now on, the process is rather different from the decompilation process used for the other functions. Here is the output of mips2c after sorting out the actor struct from Init, and with the arguments set back to `Actor* thisx`:
```C
void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
EnJj* this = THIS;
GraphicsContext *sp4C;
Gfx *sp3C;
EnJj *sp18;
Gfx *temp_v1;
GraphicsContext *temp_a1;
s32 temp_a0;
temp_a1 = globalCtx->state.gfxCtx;
sp4C = temp_a1;
Graph_OpenDisps(&sp3C, temp_a1, (const char *) "../z_en_jj.c", 0x36F);
func_800943C8(globalCtx->state.gfxCtx);
Matrix_Translate(0.0f, (cosf(this->skelAnime.curFrame * 0.076624215f) * 10.0f) - 10.0f, 0.0f, (u8)1U);
Matrix_Scale(10.0f, 10.0f, 10.0f, (u8)1U);
temp_v1 = temp_a1->polyOpa.p;
temp_a1->polyOpa.p = temp_v1 + 8;
temp_v1->words.w0 = 0xDB060020;
temp_a0 = *(&D_80A88CFC + (this->unk_30E * 4));
temp_v1->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
sp18 = this;
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, (s32) this->skelAnime.dListCount, 0, 0);
Graph_CloseDisps(&sp3C, globalCtx->state.gfxCtx, (const char *) "../z_en_jj.c", 0x382);
}
```
Notable features are the Open and Close Disps functions, and blocks of the form
```C
temp_v1 = temp_a1->polyOpa.p;
temp_a1->polyOpa.p = temp_v1 + 8;
temp_v1->words.w0 = 0xDB060020;
temp_a0 = *(&D_80A88CFC + (this->unk_30E * 4));
temp_v1->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
```
(This is a particularly simple example, since there's only one of these blocks. We will give a more involved example later.)
Each of these blocks converts into a graphics macro. They are usually (but not always) straightforward, but manually converting them is a pain, and there are sometimes special cases. To deal with them easily, we will use a tool from glank's N64 tools. To install these, follow the instructions [here](https://practicerom.com/public/packages/debian/howto.txt).
For our purposes, we only need one of the programs this provides: `gfxdis.f3dex2`.
Graphics are actually 64-bit on the Nintendo 64. This code block is a result of instructions telling the processor what to do with the graphics pointer. There are two types of graphics pointer,
- polyOpa for solid textures
- polyXlu for translucent textures
Our example is polyOpa, not surprisingly since Jabu is solid.
`words.w0` and `words.w1` contain the actual graphics instruction, in hex format. Usually, `w0` is constant and `w1` contains the arguments. To find out what sort of macro we are dealing with, we use `gfxdis.f3dex2`. `w1` is variable, but we need to give the program a constant placeholder. A common word to use is 12345678, so in this case we run
```
gfxdis.f3dex2 -x -g "POLY_OPA_DISP++" -d DB06002012345678
```
- `-x` uses hex instead of the default qu macros (never mind what those are, OoT doesn't have them)
- `-g` is used to specify which graphics pointer macro to use
- `-d` is for the graphics dword
Our standard now is to use decimal colors. If you have a constant second argument rather than a variable one, you can also use `-dc` to get decimal colors instead of the default hex.
The output looks like
```
gSPSegment(POLY_OPA_DISP++, 0x08, 0x12345678);
```
We can now replace the `0x12345678` by the actual second word. Or we could, if we had worked out what it was.
Firstly, `*(&D_80A88CFC + (this->unk_30E * 4))` is referring to a piece of data we haven't externed yet. It looks like
```
glabel D_80A88CFC
.word 0x06007698, 0x06007A98, 0x06007E98, 0x00000000, 0x00000000
```
The first three words look like pointers to assets in the actor segment, which would make sense if we're looking for textures to draw. The last two words are 0, which is strange. A check in the rest of the actor file shows that `unk_30E` only takes the values `0,1,2`. We conclude that the last two words are just padding, and can be removed. Because this data is used in a graphics macro, it will be either a displaylist or a texture. We therefore set it up to be an array of unknown pointers for now:
```C
extern UNK_PTR D_80A88CFC[];
// static Gfx* D_80A88CFC[] = { 0x06007698, 0x06007A98, 0x06007E98, }
```
It goes through further processing before it is used in the macro: `(temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000` is a conversion of a segmented address into a VRAM address. We have a macro for this too: `SEGMENTED_TO_VIRTUAL`. So after all this, the second word is
```C
SEGMENTED_TO_VIRTUAL(D_80A88CFC[this->unk_30E]);
```
and the whole macro is
```C
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_80A88CFC[this->unk_30E]));
```
The contents of a desegmentation macro used like this are almost always textures in this context, so we can replace `UNK_PTR` by `u64*`, the type for textures.
You repeat this for every block in the function.
We also have macros for Graph_OpenDisps and Graph_CloseDisps: you can replace
```C
Graph_OpenDisps(&sp3C, temp_a1, (const char *) "../z_en_jj.c", 0x36F);
```
by
```C
OPEN_DISPS(temp_a1, "../z_en_jj.c", 879);
```
(the last argument is a line number, so should be in decimal).
The function may or may not use a temp for `globalCtx->state.gfxCtx`: you have to work it out using the diff.
Once you've replaced all the blocks and the open and close with macros, you proceed with the function as usual.
Two last things: the last argument of the matrix functions tells the compiler whether to use the previously stored matrix or not, so we have the enums `MTXMODE_NEW` and `MTXMODE_APPLY` for these. And the rather weird-looking float `0.076624215f` is, of all things, `(M_PI/41.0f)` (try Wolfram Alpha for these things, and if that doesn't produce anything sensible, ask in Discord).
(The actual reason is probably that the animation is 41 frames long, but you won't necessarily spot this sort of thing for most floats)
After all that, it turns out that
```C
void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
EnJj *this = THIS;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_jj.c", 879);
func_800943C8(globalCtx->state.gfxCtx);
Matrix_Translate(0.0f, (cosf(this->skelAnime.curFrame * (M_PI/41.0f)) * 10.0f) - 10.0f, 0.0f, 1);
Matrix_Scale(10.0f, 10.0f, 10.0f, 1);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_80A88CFC[this->unk_30E]));
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
this->skelAnime.dListCount, 0, 0, this);
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_jj.c", 898);
}
```
matches apart from a couple of stack differences. This can be resolved by giving it `GlobalContext* globalCtx = globalCtx2;` at the top of the function and changing the second argument to `globalCtx2` as usual.
We have enums for the last argument of the matrix functions: `0` is `MTXMODE_NEW`, `1` is `MTXMODE_APPLY`.
Lastly, the penultimate and antepenultimate arguments of `SkelAnime_DrawFlexOpa` are actually pointers to functions, so they should be `NULL` instead of `0`.
## More examples: OverrideLimbDraw and PostLimbDraw
For more examples of graphics macros and the structure of Draw functions, we look at a function from `EnDntNormal`, which is some Deku Scrubs used in the minigame stuff in Lost Woods. This has a good selection of macros, and two functions that are commonly combined with Draw, namely OverrideLimbDraw and PostLimbDraw.
The mips2c output for
```C
void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
? sp60;
Gfx *sp48;
Gfx *sp38;
Actor *sp14;
Gfx *temp_v0;
Gfx *temp_v0_2;
Gfx *temp_v0_3;
Gfx *temp_v0_4;
Gfx *temp_v0_5;
GraphicsContext *temp_a1;
GraphicsContext *temp_s0;
s32 temp_a0;
void *temp_v1;
sp60.unk0 = (s32) D_809F5E94.unk0;
sp60.unk4 = (s32) D_809F5E94.unk4;
sp60.unk8 = (s32) D_809F5E94.unk8;
temp_a1 = globalCtx->state.gfxCtx;
temp_s0 = temp_a1;
Graph_OpenDisps(&sp48, temp_a1, (const char *) "../z_en_dnt_nomal.c", 0x6FE);
func_80093D18(globalCtx->state.gfxCtx);
temp_v0 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0 + 8;
temp_v0->words.w0 = 0xDB060020;
temp_a0 = *(&D_809F5EA0 + (thisx->unk268 * 4));
temp_v0->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
sp14 = thisx;
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
Matrix_Translate(thisx->unk21C, thisx->unk220, (bitwise f32) thisx->unk224, (u8)0U);
Matrix_Scale(0.01f, 0.01f, 0.01f, (u8)1U);
temp_v0_2 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_2 + 8;
temp_v0_2->words.w0 = 0xE7000000;
temp_v0_2->words.w1 = 0;
temp_v0_3 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_3 + 8;
temp_v0_3->words.w0 = 0xFB000000;
temp_v1 = (thisx->unk26A * 4) + &D_809F5E4C;
temp_v0_3->words.w1 = (temp_v1->unk-2 << 8) | (temp_v1->unk-4 << 0x18) | (temp_v1->unk-3 << 0x10) | 0xFF;
temp_v0_4 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_4 + 8;
temp_v0_4->words.w0 = 0xDA380003;
sp38 = temp_v0_4;
sp38->words.w1 = Matrix_NewMtx(globalCtx->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
temp_v0_5 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_5 + 8;
temp_v0_5->words.w1 = (u32) &D_06001B00;
temp_v0_5->words.w0 = 0xDE000000;
Graph_CloseDisps(&sp48, globalCtx->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x719);
if (&func_809F49A4 == thisx->unk214) {
func_80033C30((Vec3f *) &thisx->world, (Vec3f *) &sp60, (u8)0xFFU, globalCtx);
}
}
```
### Graphics macros
There are 5 graphics macro blocks here:
```C
temp_v0 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0 + 8;
temp_v0->words.w0 = 0xDB060020;
temp_a0 = *(&D_809F5EA0 + (thisx->unk268 * 4));
temp_v0->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
```
We've seen one of these before: gfxdis gives
```C
$ gfxdis.f3dex2 -g "POLY_OPA_DISP++" -d DB06002012345678
gSPSegment(POLY_OPA_DISP++, 0x08, 0x12345678);
```
and looking at the data shows
```
glabel D_809F5EA0
.word 0x060027D0, 0x060025D0, 0x06002750, 0x00000000
```
which is an array of pointers to something again. It is used inside a `SEGMENTED_TO_VIRTUAL`, so they are most likely textures, and this block becomes
```C
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_809F5EA0[this->unk_268]));
```
Next,
```C
temp_v0_2 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_2 + 8;
temp_v0_2->words.w0 = 0xE7000000;
temp_v0_2->words.w1 = 0;
```
which we can find immediately using
```
$ gfxdis.f3dex2 -g "POLY_OPA_DISP++" -d E700000000000000
gDPPipeSync(POLY_OPA_DISP++);
```
Third,
```C
temp_v0_3 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_3 + 8;
temp_v0_3->words.w0 = 0xFB000000;
temp_v1 = (thisx->unk26A * 4) + &D_809F5E4C;
temp_v0_3->words.w1 = (temp_v1->unk-2 << 8) | (temp_v1->unk-4 << 0x18) | (temp_v1->unk-3 << 0x10) | 0xFF;
```
this looks more troublesome. We find
```
$ gfxdis.f3dex2 -g "POLY_OPA_DISP++" -d FB00000012345678
gDPSetEnvColor(POLY_OPA_DISP++, 0x12, 0x34, 0x56, 0x78);
```
Now we need to work out what the last four arguments are. Two things are going on here: `D_809F5E4C` is an array of something:
```
glabel D_809F5E4C
.word 0xFFFFFFFF, 0xFFC3AFFF, 0xD2FF00FF, 0xFFFFFFFF, 0xD2FF00FF, 0xFFC3AFFF, 0xFFFFFFFF, 0xFFC3AFFF, 0xD2FF00FF
```
Worse, this is being accessed with pointer subtraction in the second word. `temp_v1 = (thisx->unk26A * 4) + &D_809F5E4C;` tells us that the array has elements of size 4 bytes, and the graphics macro implies the elements are colors. Colors of size 4 bytes are `Color_RGBA8`. Usually, we write colors in decimal, so `D_809F5E4C` becomes
```C
static Color_RGBA8 D_809F5E4C[] = {
{ 255, 255, 255, 255 }, { 255, 195, 175, 255 }, { 210, 255, 0, 255 },
{ 255, 255, 255, 255 }, { 210, 255, 0, 255 }, { 255, 195, 175, 255 },
{ 255, 255, 255, 255 }, { 255, 195, 175, 255 }, { 210, 255, 0, 255 },
};```
Now, we have two things to worry about: how to implement the negative pointer access, and how the second word is built. Negative accesses can be done by just subtracting 1, so that
```C
temp_v1 = D_809F5E4C[this->unk_26A - 1];
```
and then
```C
temp_v0_3->words.w1 = (temp_v1->unk2 << 8) | (temp_v1->unk0 << 0x18) | (temp_v1->unk3 << 0x10) | 0xFF;
```
or rather, since it is a `Color_RGB8`,
```C
temp_v0_3->words.w1 = (temp_v1.b << 8) | (temp_v1.r << 0x18) | (temp_v1.g << 0x10) | 0xFF;
```
The last thing to worry about is how to put this word into the macro. Let's think aboout what the word actually is in a concrete case; it is easiest to see what is going on in hex, so suppose we are in the case
```C
temp_v1 = { 0xFF, 0xC3, 0xAF, 0xFF };
```
Then the calculation is
```
(0xAF << 8) | (0xFF << 0x18) | (0xC3 << 0x10) | 0xFF = 0xAF00 | 0xC30000 | 0xFF0000000 | 0xFF = 0xFFC3AFFF
```
and so all this calculation is doing is turning `temp_v1` back into a word, with the last byte replaced by `0xFF` (that all the elements of `D_809F5E4C` have `0xFF` as their last element anyway is irrelevant here). Looking back at the output of gfxdis, we see that this actually means that the r,g,b just slot into the penultimate three arguments, the last being `0xFF`, leaving
```C
temp_v1 = D_809F5E4C[this->unk_26A - 1];
gDPSetEnvColor(POLY_OPA_DISP++, temp_v1.r, temp_v1.g, temp_v1.b, 0xFF);
```
as the residue of this block; it may turn out later that we can eliminate the temp.
The last two are much easier:
```C
temp_v0_4 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_4 + 8;
temp_v0_4->words.w0 = 0xDA380003;
sp38 = temp_v0_4;
sp38->words.w1 = Matrix_NewMtx(globalCtx->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
```
The macro is
```
$ gfxdis.f3dex2 -g "POLY_OPA_DISP++" -d DA38000312345678
gSPMatrix(POLY_OPA_DISP++, 0x12345678, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
```
and the second argument is filled by the `Matrix_NewMtx` function:
```C
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
```
Lastly,
```C
temp_v0_5 = temp_s0->polyOpa.p;
temp_s0->polyOpa.p = temp_v0_5 + 8;
temp_v0_5->words.w1 = (u32) &D_06001B00;
temp_v0_5->words.w0 = 0xDE000000;
```
The macro is
```
$ gfxdis.f3dex2 -g "POLY_OPA_DISP++" -d DE00000012345678
gSPDisplayList(POLY_OPA_DISP++, 0x12345678);
```
and so `D_06001B00` is a displaylist, so the type in the externed data at the top of the file can be changed to `Gfx D_06001B00[]`. Arrays act like pointers, so we don't need the `&` in the macro:
```C
gSPDisplayList(POLY_OPA_DISP++, D_06001B00);
```
Putting this all together
```C
void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
EnDntNormal *this = THIS;
? sp60;
Actor *sp14;
Color_RGBA8 temp_v1;
sp60.unk0 = (s32) D_809F5E94.unk0;
sp60.unk4 = (s32) D_809F5E94.unk4;
sp60.unk8 = (s32) D_809F5E94.unk8;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1790);
func_80093D18(globalCtx->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_809F5EA0[this->unk_268]));
sp14 = this;
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
Matrix_Translate(thisx->unk21C, thisx->unk220, (bitwise f32) thisx->unk224, (u8)0U);
Matrix_Scale(0.01f, 0.01f, 0.01f, (u8)1U);
gDPPipeSync(POLY_OPA_DISP++);
temp_v1 = D_809F5E4C[this->unk_26A - 1];
gDPSetEnvColor(POLY_OPA_DISP++, temp_v1.r, temp_v1.g, temp_v1.r, 0xFF);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, D_06001B00);
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1817);
if (&func_809F49A4 == this->unk214) {
func_80033C30((Vec3f *) &this.actor->world, (Vec3f *) &sp60, (u8)0xFFU, globalCtx);
}
}
```
### SkelAnime_Draw and the LimbDraws
Some more general tidying up can be done here (`sp60` and so `D_809F5E94` are `Vec3f`, for example, and under normal circumstances we'd know that ), but the big remaining issue is
```C
sp14 = this;
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4);
```
If we look at the definition of `SkelAnime_DrawOpa`, we find that it's missing the last argument. This is mips2c not noticing why `this` has been put on the stack: this code should actually be
```C
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4, this);
```
mips2c doing this is not especially unusual, so bear it in mind.
The other thing this tells us is that `func_809F58E4` is of type `OverrideLimbDraw`, and `func_809F59E4` of type `PostLimbDraw`. Their names are fairly self-explanatory. Filling in the prototypes as
```C
s32 func_809F58E4(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx);
void func_809F59E4(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx);
```
and running mips2c gives
```C
s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
GraphicsContext *sp38;
Gfx *sp28;
Gfx *temp_v1;
Gfx *temp_v1_2;
GraphicsContext *temp_a1;
void *temp_v0;
if ((limbIndex == 1) || (limbIndex == 3) || (limbIndex == 4) || (limbIndex == 5) || (limbIndex == 6)) {
temp_a1 = globalCtx->state.gfxCtx;
sp38 = temp_a1;
Graph_OpenDisps(&sp28, temp_a1, (const char *) "../z_en_dnt_nomal.c", 0x6C5);
temp_v1 = sp38->polyOpa.p;
sp38->polyOpa.p = temp_v1 + 8;
temp_v1->words.w1 = 0;
temp_v1->words.w0 = 0xE7000000;
temp_v1_2 = sp38->polyOpa.p;
sp38->polyOpa.p = temp_v1_2 + 8;
temp_v1_2->words.w0 = 0xFB000000;
temp_v0 = (thisx->unk26A * 4) + &D_809F5E4C;
temp_v1_2->words.w1 = (temp_v0->unk-2 << 8) | (temp_v0->unk-4 << 0x18) | (temp_v0->unk-3 << 0x10) | 0xFF;
Graph_CloseDisps(&sp28, globalCtx->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x6CF);
}
return 0;
}
void func_809F59E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3s *rot, void *thisx) {
? sp18;
sp18.unk0 = (s32) D_809F5E88.unk0;
sp18.unk4 = (s32) D_809F5E88.unk4;
sp18.unk8 = (s32) D_809F5E88.unk8;
if (thisx->unk26A == 0) {
if (limbIndex == 5) {
Matrix_MultVec3f((Vec3f *) &sp18, thisx + 0x27C);
return;
}
} else if (limbIndex == 7) {
Matrix_MultVec3f((Vec3f *) &sp18, thisx + 0x27C);
}
}
```
This structure is pretty typical: both edit what certain limbs do. Both also usually need a `ActorName *this = THIS;` at the top. We have seen both of the macros in the former before: applying the usual procedure, we find that it becomes
```C
s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
EnDntNormal *this = THIS;
if ((limbIndex == 1) || (limbIndex == 3) || (limbIndex == 4) || (limbIndex == 5) || (limbIndex == 6)) {
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1733);
gDPPipeSync(POLY_OPA_DISP++);
gDPSetEnvColor(POLY_OPA_DISP++, D_809F5E4C[this->type - 1].r, D_809F5E4C[this->type - 1].g, D_809F5E4C[this->type - 1].b, 255);
CLOSE_DISPS(globalCtx->state.gfxCtx, (const char*)"../z_en_dnt_nomal.c", 1743);
}
return 0;
}
```
Notice that this function returns `0`. OverrideLimbDraw almost always returns `0`.
The latter function is easier, and it is probably unnecessary to explain to the reader what it is necessary to do to it to clean it up.

View File

@ -1,181 +0,0 @@
# List of helper scripts
This list gives brief information on the most common usage cases. For more information, first try using `-h` or `--help` as an argument, and failing that, ask in #oot-decomp-help or #tools-other in the Discord.
## m2ctx
This generates the context for mips2c to use to type objects in its output. It lives in the tools directory. Running
```sh
./tools/m2ctx.py <path_to_c>
```
will produce a file in the root directory called `ctx.c`. You open this file and copy it into the mips2c context box.
The rule of thumb is to rerun this every time you change something significant to other functions, like the struct in the header or a function prototype, and probably after every function, at least at first. As with most other things on this project, you will develop intuition for when this is required.
## diff
This is in the repo's root directory. It is the main comparison tool to check your C code generates the right MIPS.
The usual way diff is used is
```sh
./diff.py -mwo3 <function_name>
```
- `m` automatically runs make as necessary
- `o` allows using symbol names
- `w` refreshes the diff output when the c file is saved (only the c file, not the header)
- `3` allows comparison of the previous and current saves of the file.
Many other options exist, use the `-h` to see them.
In order to use `diff.py` with the symbol names (with `o`), we need a copy of the code to compare against. This is done by copying the `build` folder into a folder called `expected`. Copying in Windows on WSL is very slow, so run
```sh
mkdir expected
cp -r build/ expected/
```
from the main directory of the repository. You should end up with the folder structure `expected/build/...`.
![Example of a diff](images/func_80A87B9C_diff1.png)
The colors have the following meanings:
- Red is lines missing
- Green is extra lines
- Blue denotes significant differences in instructions, be they just numerical ones, or whole instructions
- Yellow/Gold denotes that register usage is wrong
- Other colors are used to distinguish incorrectly used registers or stack variables, to make it easy to follow where they are used.
## decomp-permuter
This is linked in #resources in the Discord.
For inspiration when you run out of ideas to match a function. It is unlikely to match it completely by itself, but if you can't see from the MIPS or your code where you have issues, it will often tell you where to start looking.
First, import the C file and MIPS of the function to compare using
```sh
./import.py <path_to_c> <path_to_func_name.s>
```
It will put it in a subdirectory of `nonmatchings`. You then run
```sh
./permuter.py nonmatchings/<function_name>/
```
to produce suggestions. There are various arguments that can be used, of which the most important initially is `-j`: `-jN` tells it to use `N` CPU threads.
Suggestions are saved in the function directory it imported the function into.
## first_diff
Tells you where your built rom first differs from the baserom. It gives you a memory address that you can use to do, e.g. a binary diff, and also tries too find what function or data this address is in. Run with
```C
./first_diff.py
```
If the rom is shifted, the first problem will be in gDMADataTable. Ignore this and look at the next one for where you actually need to look to see what's happened. The last line makes a guess on this location you need to edit to fix the problem.
## sym_info
Gives information about a `D_address` symbol (ROM address, RAM address, file). Run
```C
./sym_info.py <D_number>
```
## ichaindis
This is used to convert the data associated to the `D_address` in
```C
Actor_ProcessInitChain(&this->actor, &D_address);
```
into an InitChain. It lives in the tools directory. Run
```sh
./tools/ichaindis.py <path_to_baserom> <D_address>
```
and copy the output. (This used to only take the ROM address, which you would need to get from `sym_info.py`. Now you can just give it the RAM address, or even the raw `D_address`.)
## colliderinit
This is used to convert data `D_address` in the various ColliderInit functions into the format of a collider. It lives in `tools/overlayhelpers`. Because there are different types of collider, you need to give it the type of collider as well. This does not need the baserom path, and a recent update allows it to be run from anywhere. You also have to give it the `<address>` without the leading `D_`.
```sh
./colliderinit.py <address> <type> <num>
```
Collider types supported are
- `ColliderJntSphInit`
- `ColliderCylinderInit`
- `ColliderTrisInit`
- `ColliderQuadInit`
- `ColliderJntSphElementInit`
- `ColliderTrisElementInit`
and `num` is used only for `ColliderJntSphElementInit`.
## sfxconvert
Automatically converts sound effect numbers in a file into their corresponding `#defines`, taking into account if `SFX_FLAG` is used. Run on a specific C file,
```sh
./tools/sfxconvert.py <path_to_file> <path_to_repo>
```
Optional arguments are `-o output` to output to a different file and `-v` to give verbose output (i.e. tell you what changes it has made).
## vt_fmt
This turns the strange strings in the `osSyncPrintf`s into the human-readable equivalent instructions. Copy the contents, including the quotation marks, and run
```sh
./tools/vt_fmt.py "contents"
```
and replace the contents of the printf with the output.
## Glank's N64 tools
In particular, the ones used to decompile graphics macros. Their use is discussed in the section on [decompiling Draw functions](draw_functions.md).
## graphovl
This generates a directed graph showing an actor's function. Search for `graphovl.py` in the Discord. Put it in the root directory of the project, and run
```sh
./graphovl.py Actor_Name
```
to produce a png in the `graphs` subdirectory.
## format
Shell script that does a standardised format to the C code. Can be run on a file, a directory, or the whole codebase. Run this before you submit a PR.
## find_unused_asm
Tracks down any `.s` files no longer used by the project. Does not ignore comments, so you have to actually remove any `#pragma` lines for it to consider the file unused.
```sh
./tools/find_unused_asm.sh
```
will output a list of all such files, while adding `-d` deletes the files.
## csdis
This converts the cutscene data into macros that the cutscene system uses. Cutscenes are generally very long, so I recommend sending the output straight to a file with `>`, rather than trying to copy it all from the terminal. Run
```sh
./tools/csdis.py <address>
```
on the address from the `D_address` containing the cutscene data.
## regconvert
This converts the direct memory references, of the form `gGameInfo->data[index]` or `gGameInfo + 0x<offset>`, into the corresponding REG macros defined in [regs.h](../include/regs.h). Run
```sh
./tools/regconvert.py <index>
```
if you have it in the form `gGameInfo->data[index]`, or
```sh
./tools/regconvert.py --offset <offset>
```
if you have it in the form `gGameInfo + 0x<offset>`. You can also run it on a whole file using `--file <path/to/file>`.
## assist
This takes a function name, and looks for functions with very similar assembly code. It outputs the best matches, and tells you if there is a decompiled one.
```sh
./tools/assist.py <function_name>
```
It has two optional arguments:
- `--threshold` adjust how high the matching threshold is, 1.0 being highest, 0.0 lowest
- `--num-out` change the number of matches to output

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

View File

@ -1,74 +0,0 @@
# Introduction to decomp
In this project, we are decompiling The Legend of Zelda: Ocarina of Time. This means that we take the assembly language that is on the cartridge,
```
glabel func_80A13098
/* 00028 80A13098 8482001C */ lh $v0, 0x001C($a0) ## 0000001C
/* 0002C 80A1309C 24010004 */ addiu $at, $zero, 0x0004 ## $at = 00000004
/* 00030 80A130A0 14410003 */ bne $v0, $at, .L80A130B0
/* 00034 80A130A4 244EFFFE */ addiu $t6, $v0, 0xFFFE ## $t6 = FFFFFFFE
/* 00038 80A130A8 10000002 */ beq $zero, $zero, .L80A130B4
/* 0003C 80A130AC A480001C */ sh $zero, 0x001C($a0) ## 0000001C
.L80A130B0:
/* 00040 80A130B0 A48E001C */ sh $t6, 0x001C($a0) ## 0000001C
.L80A130B4:
/* 00044 80A130B4 8C8F0330 */ lw $t7, 0x0330($a0) ## 00000330
/* 00048 80A130B8 24020001 */ addiu $v0, $zero, 0x0001 ## $v0 = 00000001
/* 0004C 80A130BC 24180011 */ addiu $t8, $zero, 0x0011 ## $t8 = 00000011
/* 00050 80A130C0 A1E20004 */ sb $v0, 0x0004($t7) ## 00000004
/* 00054 80A130C4 A08201B8 */ sb $v0, 0x01B8($a0) ## 000001B8
/* 00058 80A130C8 A08201B9 */ sb $v0, 0x01B9($a0) ## 000001B9
/* 0005C 80A130CC 03E00008 */ jr $ra
/* 00060 80A130D0 A0980117 */ sb $t8, 0x0117($a0) ## 00000117
```
(the commented numbers on the left are the original machine code, the middle the translation into MIPS assembly, the right useful information about the numbers in the code)
and turn it into compilable C code:
```C
void func_80A13098(EnFirefly* this) {
if (this->actor.params == 4) {
this->actor.params = 0;
} else {
this->actor.params -= 2;
}
this->collider.list->body.toucher.effect = 1;
this->auraType = 1;
this->onFire = 1;
this->actor.naviEnemyId = 0x11;
}
```
which is intended to be as close to the original code as possible. We are doing *matching* decomp: in the right context, and with the right compiler settings, the above C compiles into *precisely* the assembly code above, not just equivalent code.
N.B. We are using only publicly available code. In particular, we are not looking at any of the recent Nintendo source code leaks. (These apparently contain very little Ocarina of Time material anyway.)
Progress of the project can be found at [https://zelda64.dev]. The long-term goal of this project is to obtain a complete compilable version of the code for every publicly released version of Ocarina of Time (there are also sister projects for Majora's Mask and other Zelda games). *We are not working on a PC Port, and this project will not be making one*, although the resulting code will be very useful if someone does intend to make such a port.
Most of the discussion on the project takes place on the Zelda Decompilation Discord (linked in the README.md). We are very welcoming to newcomers and are happy to help you with any problems you might have with the decompilation process.
## What do I need to know to take part?
Basic knowledge of C, particularly arrays and pointers, is extremely useful. Knowledge of MIPS is not required initially, but if you are serious about decompilation you will soon pick up a lot of it.
Knowledge of the fundamentals of git and GitHub is required. There are a number of tutorials available online, and a later document in this tutorial describes how you contribute to this project outside the actual decompilation process.
The most useful knowledge to have is a general understanding of how the game works. An afternoon of constructive mucking about in the [Practice Rom](http://practicerom.com) (aka GZ) will be very beneficial if you have not looked at the game's subsurface workings before.
## Structure of the code
A lot of work has already been done on the code to bring it into a format that is easy to decompile. I will discuss actors, since this is where the majority of new people should begin.
An *actor* is any thing in the game that moves or performs actions or interactions: Link is an actor, enemies are actors, NPCs are actors, props like grass are actors (Fishing is also an actor, the largest one, but you don't need to know about it). The vast majority of actors are *overlays*, which means they are loaded only when the game needs them.
In the code, each actor is associated to several files: there is
- the main .c file, e.g. `src/overlays/actors/ovl_En_Firefly/z_en_firefly.c`
- the actor's Header file, e.g. `src/overlays/actors/ovl_En_Firefly/z_en_firefly.h`
- various .o files that tell the `make` script how to incorporate it into building the ROM,
and then for undecompiled actors, various assembly (.s) files, generally including:
- one for the actor's *data* (this usually includes things like its collision information about how to draw it, and various other stuff that is used in it), e.g. `data/overlays/actors/z_en_firefly.data.s`
- one for each function in the actor, e.g. `asm/non_matchings/overlays/actors/ovl_En_Firefly/func_80A13098.s`
The basic process of decomp is to take one of the .s files, run it through a decompilation program (mips_to_c) that reads the ASM very literally, and then, through humen ingenuity, reshape it into code that not only compiles in the first place, but completely matches the original code (well-written or otherwise).

View File

@ -1,97 +0,0 @@
# The merging process
## Optional: Documentation
It is helpful to document the functions and variables in the actor before you Pull Request it. The aim is to provide code that is sufficiently clear to be self-documenting, but it is worth leaving a comment on anything you find obscure or confusing. (Pull Request reviews will let you know if you are leaving too many comments.) Useful things to do documentation-wise:
- Name all (or most) of the functions.
- Name all the variables in the actor struct.
- Create enums for params, and any other numbers that would benefit from that sort of clarity.
You can test things using the practice rom for a retail version (watches and memory view is especially helpful), as well as the generated rom with Project 64 and something like Spectrum. The most important things to know if using a retail version to test are:
- all the addresses will be different
- actor structs in debug have 10 bytes of padding at the end, so subtract `0x10` from any subsequent offsets.
If you want to use `diff` after renaming anything, particularly functions, remember to copy the `build/` folder into `expected/` so use the correct symbols. *Make sure that `make` gives `OK` before doing this, or you're going to get very confused.*
Finally, *if you are not sure what something does, either ask or leave it unnamed: it will be less confusing later if things are unnamed than if they are wrongly named*
## Preparing to PR
### Change the `spec`
Specifically, to use the automatically generated reloc, rather than the original. In the case of an entirely matched actor, you find the section relating to the actor that you edited before:
```
beginseg
name "ovl_En_Jj"
include "build/src/overlays/actors/ovl_En_Jj/z_en_jj.o"
//include "build/data/overlays/actors/z_en_jj.data.o"
include "build/data/overlays/actors/z_en_jj.reloc.o"
endseg
```
and change to use our reloc:
```
beginseg
name "ovl_En_Jj"
include "build/src/overlays/actors/ovl_En_Jj/z_en_jj.o"
include "build/src/overlays/actors/ovl_En_Jj/ovl_En_Jj_reloc.o"
endseg
```
(copy the path, then copy the directory name and put `_reloc.o` after it).
### Delete the asm files.
We have a script that will detect and delete unused asm files, `find_unused_asm.py`. Running it bare will output a list of all the unused files, while passing `-d` will delete them.
This does not distinguish comments, so remove all commented references to the files themselves first. If you have left the `#pragma` lines in but commented out, the following regular expression will find them:
```
\n//.*#pragma .*?\)
```
### Non-matchings
If you can't match a function even with everyone's, don't worry overlong about it. Hopefully you can get it to do the same thing as the original (non-matching), and then you set it up to use the original asm for the matching build, and your code for the non-matching. You can look at the other partially-matched actors to see how to set this up with `#ifdef`s.
### Format
Run the formatting script `format.sh`, to format the C files in the standard way we use.
### Merge master
To make sure the PR builds correctly with the current master, you need to merge `upstream/master` before you make the PR. This tends to break things, that you have to fix to get it to compile correctly again.
## Pull Requests
Push commits to your fork of the repository on GitHub, and then open a pull request. Name the PR something sensible, like
- `EnJj OK and documented` (if all the functions match and your documentation is fairly complete)
- `EnJj OK` (if all the functions match)
- `EnJj (n nonmatching)` (if you couldn't get one or more functions to work, but to the best of your knowledge they are equivalent code)
- `EnJj (1 nonequivalent)` (if you couldn't get one or more functions to work, and do not believe the code has the same effect)
and so on, although these four tend to cover most cases. Feel free to add a comment describing anything interesting you had to do or issues in non-matchings,
### Reviews
Pull requests may be reviewed by anyone (who knows enough about the conventions of the project), but all are usually reviewed by Fig and Roman.
To implement suggestions made in reviews, it is generally easier to be consistent if you push more commits from your local branch. It is quite possible that in the meantime some other PR has gone in, and git will ask you to merge master before you add more commits. This is normally fairly painless, although often you have to resolve merge conflicts. If in doubt, backup your work before doing anything, and ask in Discord before doing anything drastic, or if you don't understand what git is telling you.
There is no need to wait for your PR to be approved and committed before working on your next actor.
## Trello
It's helpful to use the labels on Trello.
- RESERVED is obvious.
- Work in Progress is for when you're actively working on something
- Matched for when it is totally decompiled and matching
- Documented if at least everything is named and odd code is commented. We'll likely wipe these and start over when proper documentation begins.
We now have a PR label on the Trello that you can use to indicate your actor is in a PR. When the actor is committed to master, you can move the actor into the `Decompiled Files (Overlays)` column: it goes at the top if there is a non-matching, and below if not.

View File

@ -1,174 +0,0 @@
# Object Decompilation
Object decompilation is the process of taking an object file and writing instructions to extract the various assets from it in the correct format, with appropriate labelling to distinguish their nature and/or use.
## What is an object file?
An object file is generally where most of the information used by overlays is stored. Its contents can include
- Vertices (positional/normal/color data used by displaylists)
- Textures
- DisplayLists (instructions to the graphics processor on how to put together textures and vertices)
- Skeleton (The underlying structure of an actor's shape, that can be manipulated to change its "pose")
- Animations
- Prerendered backgrounds
## How we work with objects
Because these are regarded as copyrighted, we do not want them in the repository. We instead extract them from the ROM. To do this we use a system called ZAPD (Zelda Asset Processor for Decompilation). The main aim of object decompilation is to give ZAPD an XML file that tells it what the assets it is supposed to be extracting actually are, so it can put them in the right format and name them.
## How to decomp an object
Choose an object to decomp. As usual, some will be easier than others. For reasons explained shortly, it is much easier to decomp an object if all actors that use it are decompiled.
### Files and folders
Select the XML file of your selected object, which should be in `assets/xml/objects/object_name.xml`.
The ZAPD output will go in the folder `assets/objects/object_name/`. You'll want this folder open later to check the output is correct.
### Examining actor files
Most objects are used by at least one actor. For those used by an actor, we can use the script `tools/xmlcreate.py` on the actor to separate all the blobs of data in the object that we already know about. (While it is possible to do this manually, it is much simpler to run the script first and sort it out afterwards, since it won't miss anything accidentally.)
Many objects have been added in an automated way, so most constituent parts of each object are already identified, but will still need to be named and documented properly. Also, these objects usually have some blobs unreferenced by the object's own contents and hence not automatically extracted; most of the time these can be identified by looking at references in the actor which uses said object.
### Extracting assets
You can run `extract_assets.py` to extract the object's assets. Running it with no arguments extracts *everything* all over again, though. A better way is to run it with `-s` (for single file), and give it the location of the object you want to extract relative to `assets`, i.e.
```bash
./extract_assets.py -s objects/object_name
```
This should populate the folder you created earlier. ZAPD produces a C file containing the extracted object data, which will be `assets/objects/object_name/object_name.c`. Any data that you have not specified the type of, or is not referenced elsewhere in the object, is extracted as unknown blobs (usually named `unaccounted_XXXXXX`). Open the C file to see if there are any such blobs. (Some are just padding with 0s and can be ignored.)
You now have to try and decipher these blobs using the [list of tools given below](#tools) to work out what they might be. In the case of unused parts of the object, this can be very difficult.
### Naming
A significant question is how deep into the object you want to explicitly categorise and name things.
1. As a minimum, you need to include every piece of data that is directly accessed by another part of the repo (generally, but not always, actors). This allows for elimination of entries in [`undefined_syms.txt`](../../undefined_syms.txt). For most objects, this includes several of a skeleton, animations, some textures, and collision information.
2. Naming display lists that are associated to limbs in the skeleton. This is usually straightforward, providing Z64Utils or Hylian Toolbox can show the skeleton properly.
3. The next level is to name and give a format to any texture files that are produced from the extraction that are so far unnamed.
4. If you really want to you can name the limbs themselves.
5. In very rare cases, you may also want to name a particular set of vertices.
Current naming practice is to name each item in the xml using camelCase as usual, with the `g` prefix (for "global"), and the type of data last (Skel, Anim, DL, Tex), while output texture files are named in `snake_case`.
Each pass of a successive level will require extracting the single asset again.
### Textures
Textures are especially troublesome due to the abundance of formats they can be in. Some are simple RGBA textures, while others use external palettes, and can look meaningless without. If the texture is used in a displaylist, it will tell you the format, but if not, you have to use your best judgement based on anything you know about its context.
The order of operations is that palettes are loaded first, then the texture, and then the vertices to which it is applied.
The first argument of `gsDPLoadTextureBlock` tells you the offset, the second the format, the third the bit depth, fourth the width and fifth the height
The following is a list of the texture formats the Nintendo 64 supports, with their gfxdis names and ZAPD format names.
| Format name | Typing in `gsDPLoadTextureBlock` | "Format" in xml |
| ----------------------------------------------- | -------------------------------- | --------------- |
| 4-bit intensity (I) | `G_IM_FMT_I, G_IM_SIZ_4b` | i4 |
| 4-bit intensity with alpha (I/A) (3/1) | `G_IM_FMT_IA, G_IM_SIZ_4b` | ia4 |
| 4-bit color index (CI) | `G_IM_FMT_CI, G_IM_SIZ_4b` | ci4 |
| 8-bit I | `G_IM_FMT_I, G_IM_SIZ_8b` | i8 |
| 8-bit IA (4/4) | `G_IM_FMT_IA, G_IM_SIZ_8b` | ia8 |
| 8-bit CI | `G_IM_FMT_CI, G_IM_SIZ_8b` | ci8 |
| 16-bit red, green, blue, alpha (RGBA) (5/5/5/1) | `G_IM_FMT_RGBA, G_IM_SIZ_16b` | rgba16 |
| 16-bit IA (8/8) | `G_IM_FMT_IA, G_IM_SIZ_16b` | ia16 |
| 16-bit YUV (Luminance, Blue-Y, Red-Y) | `G_IM_FMT_YUV, G_IM_SIZ_16b` | (not used) |
| 32-bit RGBA (8/8/8/8) | `G_IM_FMT_RGBA, G_IM_SIZ_32b` | rgba32 |
The 4-bit formats are loaded using `gDPLoadTextureBlock_4b`. The others use `gDPLoadTextureBlock`.
For example,
```c
gsDPLoadTextureBlock(D_06006110, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, 0, 0),
```
says that there is a texture at offset `0x6110`, its Format is `rgba16`, Width is `16` and Height is `16`, so we can declare
```XML
<Texture Name="gObjectNameSomethingTex" OutName="object_name_something" Format="rgba16" Width="16" Height="16" Offset="0x6110"/>
```
See [this web page](http://n64devkit.square7.ch/tutorial/graphics/3/3_3.htm) for more information about these formats, and [gSP functions](http://n64devkit.square7.ch/n64man/gsp/gSP_INDEX.htm) and [gDP functions](http://n64devkit.square7.ch/n64man/gdp/gDP_INDEX.htm) for more about the graphics functions used.
The `ci` formats use palettes, which are declared separately. The shape you give the palette does not matter, but to avoid overlap errors it needs to fit into a rectangle; choose the one you think looks best.
If in doubt, look at completed objects in the repo, and if still in doubt, ask.
### Telling the repo to use the new files
Just as when you decomp an actor you have to change the `spec` to tell it to use the new files, you have to do a similar thing for the object. Find the appropriate section for the object you have decompiled, and replace the line
```c
include "build/baserom/object_name.o"
```
by
```c
include "build/assets/objects/object_name/object_name.o"
number 6
```
(the second line tells it to assign the object to segment 6 for the actors that use it: some objects use other segments, but you'll know this from the generated XML already: the `Segment` argument in the `File` tag will be different).
Now, add
```c
#include "objects/object_name/object_name.h"
```
to every actor that uses the file, to tell it about the new symbols you have defined.
Finally, replace all the symbols in the actors that use the file by the new names you gave them, and remove the corresponding sections in `undefined_syms.txt` and any `extern`s to the object's data in the actor files.
If you did everything correctly, you should still get OK when running `make`.
## Tools
Object decompilation is essentially a descriptive process, but it requires that we know what each blob of data in the object file actually is, and sometimes, the actor files that use an object are not sufficient to determine what everything is. Therefore it is useful to have a battery of romhacking and examination tools to bring to bear on the file to read its contents.
- The state-of-the-art is random's [Z64Utils](https://github.com/Random06457/Z64Utils). This can find and analyze the displaylists, textures and vertices in an object file, and even has an skeleton and animation viewer. It is not perfect; the best model viewer remains the debug rom itself.
- The old solution to look at skeletons and animations is [Hylian Toolbox](http://wiki.maco64.com/Tools/Hylian_Toolbox). This suffers from numerous issues, but is usually suitable for looking at object files that contain one skeleton and a few animations.
- To look at textures that you know something about, a texture viewer such as [Texture64](https://github.com/queueRAM/Texture64) is often useful. You may have trouble determining things like the palette a texture uses, depending on the format.
## Building and investigative modding
Thankfully it is not necessary to do a full make from clean to check that a particular object file has been decompiled successfully.
- With a valid xml file, run `extract_assets.py -s` on its object.
- `make`
If you want to change a texture, for example to see precisely where it is used, the following steps ensure it will be used in the build
- Make sure the `spec` is updated to use the generated assets (see above)
- Change and save the texture
- Touch the C file in the same directory (that includes it)
- make
- Ironically, ERROR 1 implies success (your new texture has changed the checksum).
If you'd rather not have it tell you about the checksum, you can run `make COMPARE=0` instead.
---
To revert to the original texture, you can just run `extract_assets.py -s` on the object again.
N.B. doing this will overwrite every custom texture, as will running `make setup`.
## Example
An example of decompiling a particular object is given [here](object_decomp_example.md).

View File

@ -1,258 +0,0 @@
# Object Decompilation Example
A fairly typical example of an NPC's object is `object_bg`. It is used by one actor: `ovl_En_Bom_Bowl_Man`.
## First pass: getting it to compile
Running `tools/xmlcreate.py` gives
```xml
$ python3 tools/xmlcreate.py src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c chuGirl
Unknown type at offset 004110
Unknown type at offset 004910
Unknown type at offset 005110
<Root>
<File Name="object_bg" Segment="6">
<Skeleton Name="gchuGirlSkel_006EB0" Type="Flex" LimbType="Standard" Offset="0x6EB0"/>
<Animation Name="gchuGirlAnim_000710" Offset="0x710"/>
<Animation Name="gchuGirlAnim_000080" Offset="0x80"/>
<Animation Name="gchuGirlAnim_0072AC" Offset="0x72AC"/>
<!-- <UNK_PTR Name="gchuGirlUnknown_004110" Offset="0x4110"/> -->
<!-- <UNK_PTR Name="gchuGirlUnknown_004910" Offset="0x4910"/> -->
<!-- <UNK_PTR Name="gchuGirlUnknown_005110" Offset="0x5110"/> -->
</File>
</Root>
```
We have two issues here that need to be resolved: naming the animations and sorting out the unknown things.
### Animations
You have three choices to work out what the animations are:
- Read the code and look at them in the game.
- Hylian Toolbox
- The latest versions of Z64Utils
The first of these is probably simplest if you know the game and the actor well. In this case, we know that she is dozing when you first enter, wakes up when you talk to her, then leans on the counter with both hands. We can thus name them accordingly.
Hylian Toolbox is terrible, but good for quick-and-dirty things like finding out what a particular animation does without booting up the game.
Z64Utils is way better than Hylian Toolbox, but still in development.
### Unknowns
Looking in the actor, the unknowns are assigned to segment 8 using `SEGMENTED_TO_VIRTUAL`. This indicates textures. To find out what type they are, we can find the displaylist that uses them, and look at it in Z64Utils: if we look at the object in the object analyser, then find the right displaylist, it will not display correctly in the DList viewer, asking for a texture to put on 08000000. Giving it one of the textures, we discover that it is the head displaylist and the textures are eye textures. Hence we can name them `gChuGirlEyeOpen/Half/ClosedTex` (we equivocate on half-open/half-closed since many actors use the half texture for both opening and closing). From the code in the displaylist that loads it, we can also extract the texture's format, namely
```c
06002FD8: gsDPLoadTextureBlock(D_08000000, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 5, 5, 0, 0),
```
So all three are `Format="rgba16" Width="32" Height="32"`.
```xml
<Root>
<File Name="object_bg" Segment="6">
<!-- Bombchu Bowling Girl skeleton -->
<Skeleton Name="gChuGirlSkel" Type="Flex" LimbType="Standard" Offset="0x6EB0"/>
<!-- Bombchu Bowling Girl animations -->
<Animation Name="gChuGirlWakeUpAnim" Offset="0x80"/>
<Animation Name="gChuGirlNoddingOffAnim" Offset="0x710"/>
<Animation Name="gChuGirlLeanOverCounterAnim" Offset="0x72AC"/>
<!-- Bombchu Bowling Girl eye textures -->
<Texture Name="gChuGirlEyeOpenTex" OutName="chu_girl_eye_open" Format="rgba16" Width="32" Height="32" Offset="0x4110"/>
<Texture Name="gChuGirlEyeHalfTex" OutName="chu_girl_eye_half" Format="rgba16" Width="32" Height="32" Offset="0x4910"/>
<Texture Name="gChuGirlEyeClosedTex" OutName="chu_girl_eye_closed" Format="rgba16" Width="32" Height="32" Offset="0x5110"/>
</File>
</Root>
```
Having got this far, we can now run
```bash
./extract_assets.py -s objects/object_bg
```
to extract the contents of the object into the new folder, change the spec to use our newly extracted assets:
```txt
beginseg
name "object_bg"
romalign 0x1000
include "build/baserom/object_bg.o"
endseg
```
to
```txt
beginseg
name "object_bg"
romalign 0x1000
include "build/assets/objects/object_bg/object_bg.o"
number 6
endseg
```
and wipe the `z_en_bom_bowl_man` section from `undefined_syms.txt`:
```txt
// z_en_bom_bowl_man
D_06006EB0 = 0x06006EB0;
D_06000710 = 0x06000710;
D_06000080 = 0x06000080;
D_060072AC = 0x060072AC;
```
Now `make` should give OK.
## The displaylists
For this step, we use Hylian Toolbox; if you have more than one skeleton in your actor, Hylian Toolbox will only show the first one. The others can be examined in the latest version of Z64Utils. Z64Utils can also give you a list of every displaylist in an object, be it just for cross-checking or to find extras.
Opening the rom in Hylian Toolbox and looking at object_bg, we can note down the displaylist associated to each limb.
In this case naming is easy: we just have to note down the limb each is attached to. We only need a name and offset, and we end up with:
```xml
<Root>
<File Name="object_bg" Segment="6">
<!-- Bombchu Bowling Girl skeleton -->
<Skeleton Name="gChuGirlSkel" Type="Flex" LimbType="Standard" Offset="0x6EB0"/>
<!-- Bombchu Bowling Girl animations -->
<Animation Name="gChuGirlWakeUpAnim" Offset="0x80"/>
<Animation Name="gChuGirlNoddingOffAnim" Offset="0x710"/>
<Animation Name="gChuGirlLeanOverCounterAnim" Offset="0x72AC"/>
<!-- Bombchu Bowling Girl limb displaylists -->
<DList Name="gChuGirlWaistDL" Offset="0x4038"/>
<DList Name="gChuGirlTorsoDL" Offset="0x3DB0"/>
<DList Name="gChuGirlNeckDL" Offset="0x33C8"/>
<DList Name="gChuGirlHeadDL" Offset="0x2EE0"/>
<DList Name="gChuGirlLeftUpperArmDL" Offset="0x3780"/>
<DList Name="gChuGirlLeftForearmDL" Offset="0x3670"/>
<DList Name="gChuGirlLeftHandDL" Offset="0x3520"/>
<DList Name="gChuGirlRightUpperArmDL" Offset="0x3BC8"/>
<DList Name="gChuGirlRightForearmDL" Offset="0x3AB8"/>
<DList Name="gChuGirlRightHandDL" Offset="0x3968"/>
<!-- Bombchu Bowling Girl eye textures -->
<Texture Name="gChuGirlEyeOpenTex" OutName="chu_girl_eye_open" Format="rgba16" Width="32" Height="32" Offset="0x4110"/>
<Texture Name="gChuGirlEyeHalfTex" OutName="chu_girl_eye_half" Format="rgba16" Width="32" Height="32" Offset="0x4910"/>
<Texture Name="gChuGirlEyeClosedTex" OutName="chu_girl_eye_closed" Format="rgba16" Width="32" Height="32" Offset="0x5110"/>
</File>
</Root>
```
Checking the C file, these are all of the displaylists in the actor, so we can move on.
## The rest of the textures
This is the difficult bit: we have to work out what each texture in the extracted pile is actually used for. A lot of this can be done in Z64Utils, but sometimes it is necessary to check in-game, especially for the weirder-looking ones. You can edit a texture file and compile the rom (which shouldn't match any more if you did it successfully) to make it easier to find.
```xml
<Root>
<File Name="object_bg" Segment="6">
<!-- Bombchu Bowling Girl skeleton -->
<Skeleton Name="gChuGirlSkel" Type="Flex" LimbType="Standard" Offset="0x6EB0"/>
<!-- Bombchu Bowling Girl animations -->
<Animation Name="gChuGirlWakeUpAnim" Offset="0x80"/>
<Animation Name="gChuGirlNoddingOffAnim" Offset="0x710"/>
<Animation Name="gChuGirlLeanOverCounterAnim" Offset="0x72AC"/>
<!-- Bombchu Bowling Girl limb displaylists -->
<DList Name="gChuGirlWaistDL" Offset="0x4038"/>
<DList Name="gChuGirlTorsoDL" Offset="0x3DB0"/>
<DList Name="gChuGirlNeckDL" Offset="0x33C8"/>
<DList Name="gChuGirlHeadDL" Offset="0x2EE0"/>
<DList Name="gChuGirlLeftUpperArmDL" Offset="0x3780"/>
<DList Name="gChuGirlLeftForearmDL" Offset="0x3670"/>
<DList Name="gChuGirlLeftHandDL" Offset="0x3520"/>
<DList Name="gChuGirlRightUpperArmDL" Offset="0x3BC8"/>
<DList Name="gChuGirlRightForearmDL" Offset="0x3AB8"/>
<DList Name="gChuGirlRightHandDL" Offset="0x3968"/>
<!-- Bombchu Bowling Girl limb textures -->
<Texture Name="gChuGirlMouthTex" OutName="chu_girl_mouth" Format="rgba16" Width="32" Height="32" Offset="0x5910"/>
<Texture Name="gChuGirlSkinGradientTex" OutName="chu_girl_skin_gradient" Format="rgba16" Width="16" Height="16" Offset="0x6110"/>
<Texture Name="gChuGirlSweaterTex" OutName="chu_girl_sweater" Format="rgba16" Width="32" Height="32" Offset="0x6510"/>
<Texture Name="gChuGirlUmbEarLicusTex" OutName="chu_girl_umb_ear_licus" Format="rgba16" Width="16" Height="16" Offset="0x6310"/>
<Texture Name="gChuGirlHairTex" OutName="chu_girl_hair" Format="rgba16" Width="8" Height="16" Offset="0x6D10"/>
<!-- Bombchu Bowling Girl eye textures -->
<Texture Name="gChuGirlEyeOpenTex" OutName="chu_girl_eye_open" Format="rgba16" Width="32" Height="32" Offset="0x4110"/>
<Texture Name="gChuGirlEyeHalfTex" OutName="chu_girl_eye_half" Format="rgba16" Width="32" Height="32" Offset="0x4910"/>
<Texture Name="gChuGirlEyeClosedTex" OutName="chu_girl_eye_closed" Format="rgba16" Width="32" Height="32" Offset="0x5110"/>
</File>
</Root>
```
## Final pass
Therefore, we end up with the following:
```xml
<Root>
<File Name="object_bg" Segment="6">
<!-- Bombchu Bowling Girl skeleton -->
<Skeleton Name="gChuGirlSkel" Type="Flex" LimbType="Standard" Offset="0x6EB0"/>
<!-- Bombchu Bowling Girl animations -->
<Animation Name="gChuGirlWakeUpAnim" Offset="0x80"/>
<Animation Name="gChuGirlNoddingOffAnim" Offset="0x710"/>
<Animation Name="gChuGirlLeanOverCounterAnim" Offset="0x72AC"/>
<!-- Bombchu Bowling Girl limb displaylists -->
<DList Name="gChuGirlWaistDL" Offset="0x4038"/>
<DList Name="gChuGirlTorsoDL" Offset="0x3DB0"/>
<DList Name="gChuGirlNeckDL" Offset="0x33C8"/>
<DList Name="gChuGirlHeadDL" Offset="0x2EE0"/>
<DList Name="gChuGirlLeftUpperArmDL" Offset="0x3780"/>
<DList Name="gChuGirlLeftForearmDL" Offset="0x3670"/>
<DList Name="gChuGirlLeftHandDL" Offset="0x3520"/>
<DList Name="gChuGirlRightUpperArmDL" Offset="0x3BC8"/>
<DList Name="gChuGirlRightForearmDL" Offset="0x3AB8"/>
<DList Name="gChuGirlRightHandDL" Offset="0x3968"/>
<!-- Bombchu Bowling Girl limbs -->
<Limb Name="gChuGirlWaistLimb" LimbType="Standard" Offset="0x6E10"/>
<Limb Name="gChuGirlTorsoLimb" LimbType="Standard" Offset="0x6E1C"/>
<Limb Name="gChuGirlNeckLimb" LimbType="Standard" Offset="0x6E28"/>
<Limb Name="gChuGirlHeadLimb" LimbType="Standard" Offset="0x6E34"/>
<Limb Name="gChuGirlLeftUpperArmLimb" LimbType="Standard" Offset="0x6E40"/>
<Limb Name="gChuGirlLeftForearmLimb" LimbType="Standard" Offset="0x6E4C"/>
<Limb Name="gChuGirlLeftHandLimb" LimbType="Standard" Offset="0x6E58"/>
<Limb Name="gChuGirlRightUpperArmLimb" LimbType="Standard" Offset="0x6E64"/>
<Limb Name="gChuGirlRightForearmLimb" LimbType="Standard" Offset="0x6E70"/>
<Limb Name="gChuGirlRightHandLimb" LimbType="Standard" Offset="0x6E7C"/>
<!-- Bombchu Bowling Girl limb textures -->
<Texture Name="gChuGirlMouthTex" OutName="chu_girl_mouth" Format="rgba16" Width="32" Height="32" Offset="0x5910"/>
<Texture Name="gChuGirlSkinGradientTex" OutName="chu_girl_skin_gradient" Format="rgba16" Width="16" Height="16" Offset="0x6110"/>
<Texture Name="gChuGirlSweaterTex" OutName="chu_girl_sweater" Format="rgba16" Width="32" Height="32" Offset="0x6510"/>
<Texture Name="gChuGirlUmbEarLicusTex" OutName="chu_girl_umb_ear_licus" Format="rgba16" Width="16" Height="16" Offset="0x6310"/>
<Texture Name="gChuGirlHairTex" OutName="chu_girl_hair" Format="rgba16" Width="8" Height="16" Offset="0x6D10"/>
<!-- Bombchu Bowling Girl eye textures -->
<Texture Name="gChuGirlEyeOpenTex" OutName="chu_girl_eye_open" Format="rgba16" Width="32" Height="32" Offset="0x4110"/>
<Texture Name="gChuGirlEyeHalfTex" OutName="chu_girl_eye_half" Format="rgba16" Width="32" Height="32" Offset="0x4910"/>
<Texture Name="gChuGirlEyeClosedTex" OutName="chu_girl_eye_closed" Format="rgba16" Width="32" Height="32" Offset="0x5110"/>
</File>
</Root>
```
This was an easier object to do, both because it's a fairly simple collection of stuff associated to a single actor, and because a lot of the typing was already known.

View File

@ -1,830 +0,0 @@
# The rest of the functions in the actor
Up: [Contents](contents.md)
Previous: [Beginning decompilation: the Init function and the Actor struct](beginning_decomp.md)
## Now what?
Following the scheme we gave last time, we have three options:
- `func_80A87BEC`
- `func_80A87C30`
- `func_80A87F44`
Another option is to look at `Destroy`, which for smaller actors can often be done straight after Init, since it usually just removes colliders and deallocates dynapoly. However, glancing at the three given functions' assembly, there is an obvious standout:
```MIPS
glabel func_80A87F44
/* 00744 80A87F44 AFA40000 */ sw $a0, 0x0000($sp)
/* 00748 80A87F48 03E00008 */ jr $ra
/* 0074C 80A87F4C AFA50004 */ sw $a1, 0x0004($sp)
```
This is a classic "function with two arguments that does nothing". So we can simply comment out the appropriate pragma and put
```C
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx) {
}
```
in the C file.
## Destroy
Destroy will be a dead end, but we might as well do it now. Remaking the context and using mips2c on it (main 4 function, so change the prototype to use `EnJj* this`!) gives
```C
void EnJj_Destroy(EnJj *this, GlobalContext *globalCtx) {
GlobalContext *temp_a3;
s16 temp_v0;
temp_v0 = this->dyna.actor.params;
temp_a3 = globalCtx;
if (temp_v0 == -1) {
globalCtx = temp_a3;
DynaPoly_DeleteBgActor(temp_a3, &temp_a3->colCtx.dyna, (s32) this->dyna.bgId);
Collider_DestroyCylinder(globalCtx, &this->collider);
return;
}
if ((temp_v0 != 0) && (temp_v0 != 1)) {
return;
}
DynaPoly_DeleteBgActor(temp_a3, &temp_a3->colCtx.dyna, (s32) this->dyna.bgId);
}
```
Again remember to return the first argument to `Actor* this` and put `EnJj* this = THIS;` in the function body. Based on what we know about this actor already, we expect this to be another switch. Rearranging it as such, and removing the likely fake `temp_v0` gives
```C
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnJj* this = THIS;
GlobalContext* temp_a3;
temp_a3 = globalCtx;
switch (this->dyna.actor.params) {
case -1:
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
Collider_DestroyCylinder(globalCtx, &this->collider);
break;
case 0:
case 1:
DynaPoly_DeleteBgActor(temp_a3, &temp_a3->colCtx.dyna, this->dyna.bgId);
break;
}
}
```
Using `./diff.py -mwo3 EnJj_Destroy` shows that this matches already, but it seems like the temp usage should be more consistent. A little experimentation shows that
```C
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnJj* this = THIS;
switch (this->dyna.actor.params) {
case -1:
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
Collider_DestroyCylinder(globalCtx, &this->collider);
break;
case 0:
case 1:
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
break;
}
}
```
also matches, with no need for the `GlobalContext*` temp.
## Action Functions
### `func_80A87BEC`
Of the two functions we have available, `func_80A87BEC` is shorter, so we do that next. Since we haven't changed any types or header file information, there is no need to remake the context. mips2c gives
```C
void func_80A87BEC(EnJj *this, GlobalContext *globalCtx) {
if (this->dyna.actor.xzDistToPlayer < 300.0f) {
func_80A87800(this, &func_80A87B9C);
}
}
```
We see that this function just sets another action function when Link is close enough to the actor. All we have to do to this is remove the `&`, and prototype `func_80A87B9C` to be an action function. Notably, this time it is not used before it is defined, so we don't need a prototype at the top: putting a placeholder one in at the function position will do, i.e. our total edits this time are
```C
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/func_80A87B9C.s")
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx);
// #pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/func_80A87BEC.s")
void func_80A87BEC(EnJj *this, GlobalContext *globalCtx) {
if (this->dyna.actor.xzDistToPlayer < 300.0f) {
func_80A87800(this, func_80A87B9C);
}
}
```
We can now either follow this chain of action functions down, or start with the other one. We will go down in this case: it is usually easier to keep track that way.
### `func_80A87B9C`
We can remake the context, but it's simpler to just stick the function prototype we made at the bottom of the context. Either way, mips2c gives us
```C
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
s16 temp_v0;
temp_v0 = this->unk308;
if ((s32) temp_v0 >= -0x1450) {
this->unk308 = (s16) (temp_v0 - 0x66);
if ((s32) this->unk308 < -0xA28) {
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->unk14C);
}
}
}
```
Here's a new variable for our actor struct! Don't be deceived by the `s32` cast in the comparison: mips2c always does that if it's not sure. The reliable one is the `s16` cast lower down. (An `s32` doesn't fit in the space we have anyway). So the actor struct is now
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ SkelAnime skelAnime;
/* 0x01A8 */ Vec3s jointTable[22];
/* 0x022C */ Vec3s morphTable[22];
/* 0x02B0 */ ColliderCylinder collider;
/* 0x02FC */ EnJjActionFunc actionFunc;
/* 0x0300 */ Actor* childActor;
/* 0x0304 */ char unk_304[0x4];
/* 0x0308 */ s16 unk_308;
/* 0x030A */ s16 unk_30A;
/* 0x030C */ char unk_30C[0x2];
/* 0x030E */ s8 unk_30E;
/* 0x030F */ s8 unk_30F;
/* 0x0310 */ s8 unk_310;
/* 0x0311 */ s8 unk_311;
/* 0x0312 */ char unk_312[0x2];
} EnJj; // size = 0x0314
```
We can eliminate the temp since it's used in a simple way one after the other. `this->unk308 = (s16) (this->unk308 - 0x66);` can be written as `this->unk308 -= 0x66;`.
In the `func_8003EBF8` we see that we should have at least made `this->childActor` a `DynaPolyActor*`, so that the last argument is its `bgId`. To avoid compiler warnings, we also need to cast the `Actor_SpawnAsChild` as such in Init,
```C
this->childActor = (DynaPolyActor*)Actor_SpawnAsChild(...)
```
Doing so, we are left with
```C
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
if (this->unk_308 >= -0x1450) {
this->unk_308 -= 0x66;
if (this->unk_308 < -0xA28) {
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->bgId);
}
}
}
```
The diff shows this doesn't match:
![func_80A87B9C diff 1](images/func_80A87B9C_diff1.png)
It's not obvious why this doesn't match: the branching is correct, but it's loading stuff in the wrong order. Now is therefore a good time to introduce the permuter.
### The permuter
The permuter is a useful program for when you run out of ideas: it assigns a function a score based on how much it differs from the original code, then does random stuff that is known to improve matching, keeping ones that give better scores. It is not going to fix your control flow, but it does reasonably well on instruction differences and regalloc. It also has an option to worry about stack differences as well (`--stack-diffs`).
To use the permuter, clone the decomp-permuter repo from the link given in Discord. First, import the C file and MIPS of the function to compare using
```sh
./import.py <path_to_c> <path_to_func_name.s>
```
It will put it in a subdirectory of `nonmatchings`. You then run
```sh
./permuter.py nonmatchings/<function_name>/
```
to produce suggestions. There are various arguments that can be used, of which the most important initially is `-j`: `-jN` tells it to use `N` CPU threads.
Suggestions are saved in the directory it imported the function into.
![Permuter console output](images/permuter_console_output.png)
The first suggestion looks plausible:
```C
--- before
+++ after
@@ -1390,12 +1390,14 @@
} EnJj;
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx)
{
- if (this->unk_308 >= (-0x1450))
+ DynaPolyActor *new_var;
+ new_var = this->childActor;
+ if (this->unk_308 > ((-0x1450) - 1))
{
this->unk_308 -= 0x66;
if (this->unk_308 < (-0xA28))
{
- func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->bgId);
+ func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, new_var->bgId);
}
}
```
In particular, adding a temp for the actor. Some of the rest is rather puzzling, but let's just try the actor temp,
```C
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
DynaPolyActor* child = this->childActor;
if (this->unk_308 >= -0x1450) {
this->unk_308 -= 0x66;
if (this->unk_308 < -0xA28) {
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
}
}
}
```
![func_80A87B9C diff 2](images/func_80A87B9C_diff2.png)
Hooray, that worked. The function now matches (as you can check by running `make -j`). In this case we are lucky and got a couple of 0s almost immediately. This will often not be the case, and you may have to go through multiple iterations to improve things. Or you get more ideas for what to do without the permuter necessarily doing everything for you.
However, the hex values look a bit strange, and it turns out the decimal equivalents look less strange, so it's a good idea to translate them:
```C
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
DynaPolyActor* child = this->childActor;
if (this->unk_308 >= -5200) {
this->unk_308 -= 102;
if (this->unk_308 < -2600) {
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
}
}
}
```
With that, we have reached the end of this action function chain, and now have to look at `func_80A87C30`
### `func_80A87C30`
Remaking the context and running mips2c on the assembly gives
```C
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
if ((Math_Vec3f_DistXZ(&D_80A88CF0, globalCtx->unk1C44 + 0x24) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
this->unk_30C = 0x64;
func_80A87800(this, &func_80A87CEC);
}
this->collider.dim.pos.x = -0x4DD;
this->collider.dim.pos.y = 0x14;
this->collider.dim.pos.z = -0x30;
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, (Collider *) &this->collider);
}
```
If you know anything about this game, this is obviously the function that begins the process of the swallowing Link cutscene. Performing minor cleanups reduces us to
```C
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
if ((Math_Vec3f_DistXZ(&D_80A88CF0, globalCtx->unk1C44 + 0x24) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
this->unk_30C = 100;
func_80A87800(this, func_80A87CEC);
}
this->collider.dim.pos.x = -1245;
this->collider.dim.pos.y = 20;
this->collider.dim.pos.z = -48;
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);
}
```
There are three things left to do to this function:
- prototype the new action function, `func_80A87CEC`. This one is used before its definition, so needs to be prototyped at the top of the file.
- extern `D_80A88CF0`, and since the arguments of `Math_Vec3f_DistXZ` are `Vec3f`s, convert it to floats. To do float conversion, either use an online converter, or get an extension for VSCode that can do it. The data becomes
```C
extern Vec3f D_80A88CF0;
// static Vec3f D_80A88CF0 = { -1589.0f, 53.0f, -43.0f };
```
(you must include the `.0f` parts even for integer floats: it can affect codegen, and as such it is part of our style).
- replace the mysterious `globalCtx->unk1C44 + 0x24`. The first part is so common that most people on decomp know it by heart: it is the location of the Player actor. `+ 0x24` is obviously an offset that leats to a `Vec3f`, and if you look in the actor struct, you find that this is the location of `world.pos`. To use `Player`, we put `Player* player = GET_PLAYER(globalCtx)` at the top of the function.
**NOTE:** mips_to_c will now output something like `&globalCtx->actorCtx.actorLists[2].head` for the Player pointer instead: this makes a lot more sense, but is not so easy to spot in the ASM without the characteristic `1C44`.
After all this, the function becomes
```C
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
this->unk_30C = 100;
func_80A87800(this, func_80A87CEC);
}
this->collider.dim.pos.x = -1245;
this->collider.dim.pos.y = 20;
this->collider.dim.pos.z = -48;
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);
}
```
One issue we have swept under the carpet thus far is what `unk_30C` is: we still have it as padding. For this we have to look at the MIPS, since mips2c hasn't told us. Scanning through the file, we find
```MIPS
/* 00498 80A87C98 A60E030C */ sh $t6, 0x030C($s0) ## 0000030C
```
which tells us that `unk_30C` is an `s16`, filling another gap in the struct:
```C
typedef struct EnJj {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ SkelAnime skelAnime;
/* 0x01A8 */ Vec3s jointTable[22];
/* 0x022C */ Vec3s morphTable[22];
/* 0x02B0 */ ColliderCylinder collider;
/* 0x02FC */ EnJjActionFunc actionFunc;
/* 0x0300 */ DynaPolyActor* childActor;
/* 0x0304 */ char unk_304[0x4];
/* 0x0308 */ s16 unk_308;
/* 0x030A */ s16 unk_30A;
/* 0x030C */ s16 unk_30C;
/* 0x030E */ s8 unk_30E;
/* 0x030F */ s8 unk_30F;
/* 0x0310 */ s8 unk_310;
/* 0x0311 */ s8 unk_311;
/* 0x0312 */ char unk_312[0x2];
} EnJj; // size = 0x0314
```
The diff now looks fine for this function, but it gives compiler warnings about `CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);`: the last argument is the wrong type: we need to give it `&this->collider.base` instead, which points to the same address, but is the right type. So the matching function is
```C
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
this->unk_30C = 100;
func_80A87800(this, func_80A87CEC);
}
this->collider.dim.pos.x = -1245;
this->collider.dim.pos.y = 20;
this->collider.dim.pos.z = -48;
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
```
Again we have only one choice for our next function, namely `func_80A87CEC`.
### `func_80A87CEC`
Remaking the context and running mips2c on the assembly gives
```C
void func_80A87CEC(EnJj *this, GlobalContext *globalCtx) {
DynaPolyActor *sp1C;
DynaPolyActor *temp_v1;
s16 temp_v0;
temp_v0 = this->unk_30C;
temp_v1 = this->childActor;
if ((s32) temp_v0 > 0) {
this->unk_30C = temp_v0 - 1;
return;
}
sp1C = temp_v1;
globalCtx = globalCtx;
func_80A87800(this, &func_80A87EF0);
globalCtx->csCtx.segment = &D_80A88164;
gSaveContext.cutsceneTrigger = (u8)1U;
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, (s32) temp_v1->bgId);
func_8005B1A4(globalCtx->cameraPtrs[globalCtx->activeCamera]);
gSaveContext.unkEDA = (u16) (gSaveContext.unkEDA | 0x400);
func_80078884((u16)0x4802U);
}
```
Easy things to sort out:
- `func_80A87EF0` is another action function. Again it is defined below, so needs a prototype at the top.
- We have another unknown symbol, `D_80A88164`. This is the massive chunk of data that makes up the cutscene (of Jabu swallowing Link). We will worry about it when we have decompiled the rest of the actor. For now just extern it as `UNK_TYPE`.
- We can remove the casts from `(u8)1U` and just leave `1`.
- `globalCtx->cameraPtrs[globalCtx->activeCamera]` has a macro: it is `GET_ACTIVE_CAM(globalCtx)`, so this line can be written as
```C
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
```
- `gSaveContext.unkEDA` we have dealt with before: it is `gSaveContext.eventChkInf[3]`. This is a flag-setting function; it can be written more compactly as
```C
gSaveContext.unkEDA |= 0x400
```
- The last function is an audio function: we can look up the argument in `sfx.h` and find it is `NA_SE_SY_CORRECT_CHIME`
It remains to work out which, if any, of the temps are real. Based on our previous experience, we expect `temp_v1` to be real. `sp1C` is unused and hence unlikely to be real. `temp_v0` is only used in the short if and so probably not real. Checking the diff shows that our suspicions were correct:
```C
void func_80A87CEC(EnJj *this, GlobalContext *globalCtx) {
DynaPolyActor *child = this->childActor;
if (this->unk_30C > 0) {
this->unk_30C--;
return;
}
func_80A87800(this, func_80A87EF0);
globalCtx->csCtx.segment = &D_80A88164;
gSaveContext.cutsceneTrigger = 1;
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
gSaveContext.eventChkInf[3] |= 0x400;
func_80078884(NA_SE_SY_CORRECT_CHIME);
}
```
matches, but generates a complier warning for `func_8005B1A4`, which it can't find. To fix this, add it to `functions.h`, in as near as possible the correct position in numerical order. Some detective work with VSCode's Search shows that this function lives in `z_camera.c`, and its prototype is `s16 func_8005B1A4(Camera* camera)`, so add this line to `functions.h` at the bottom of the camera functions part.
Lastly, we prefer to limit use of early `return`s, and use `else`s instead if possible. That applies here: the function can be rewritten as
```C
void func_80A87CEC(EnJj* this, GlobalContext* globalCtx) {
DynaPolyActor* child = this->childActor;
if (this->unk_30C > 0) {
this->unk_30C--;
} else {
func_80A87800(this, func_80A87EF0);
globalCtx->csCtx.segment = &D_80A88164;
gSaveContext.cutsceneTrigger = 1;
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
gSaveContext.eventChkInf[3] |= 0x400;
func_80078884(NA_SE_SY_CORRECT_CHIME);
}
}
```
and still match. (Early `return`s are used after an `Actor_Kill` and in a few other situations, but generally avoided for `else`s elsewhere if possible. Talking of which...)
## `func_80A87EF0`
mips2c with updated context gives
```C
void func_80A87EF0(EnJj *this, GlobalContext *globalCtx) {
char *temp_a0;
u16 temp_v0;
temp_v0 = (u16) this->unk_30A;
if ((temp_v0 & 4) == 0) {
this->unk_30A = temp_v0 | 4;
temp_a0 = this->unk_304;
if (temp_a0 != 0) {
this = this;
Actor_Kill((Actor *) temp_a0);
this->dyna.actor.child = NULL;
}
}
}
```
Now we're a bit stuck: this tells us that `this->unk_304` is an `Actor*`, but we know nothing else about it. So just make it an actor for the time being. As before, `this->unk_304` is a pointer, so we should compare `temp_a0` to `NULL`.
We also find in the MIPS
```MIPS
lhu $v0, 0x030A($a0)
```
which at last tells us that `unk_30A` is actually a `u16`. We can now eliminate `temp_v0`, and replace the ` == 0` by a `!(...)`, which leaves
```C
void func_80A87EF0(EnJj *this, GlobalContext *globalCtx) {
Actor *temp_a0;
if (!(this->unk_30A & 4)) {
this->unk_30A |= 4;
temp_a0 = this->unk_304;
if (temp_a0 != 0) {
Actor_Kill(temp_a0);
this->dyna.actor.child = NULL;
}
}
}
```
although we are as yet none the wiser as to which actor `unk_304` actually points to.
Again we have run out of action functions. The rules suggest that we now look at Update.
## Update
Update runs every frame and updates the properties of the actor, and usually runs the action functions once per frame. As before we change the first argument to `EnJj* this` to get it to use our actor's struct. mips2c gives
```C
void EnJj_Update(EnJj *this, GlobalContext *globalCtx) {
if ((globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->unk1D94 != 0)) {
func_80A87D94();
} else {
this->actionFunc(this);
if (this->skelAnime.curFrame == 41.0f) {
Audio_PlayActorSound2((Actor *) this, (u16)0x28B6U);
}
}
func_80A87B1C(this);
SkelAnime_Update(&this->skelAnime);
Actor_SetScale((Actor *) this, 0.087f);
this->skelAnime.jointTable->unk40 = (s16) this->unk_308;
}
```
This has several problems: firstly, the action function is called with the wrong argument. We should thus be suspicious of previous functions this actor calls, and decompile them mith mips2c without context if necessary, if only to find out how many arguments they have. We find that `func_80A87D94` definitely takes `EnJj* this, GlobalContext* globalCtx` as arguments. Again, put this prototype at the function location above to avoid compiler warnings.
`unk40` of an array of `Vec3s`s is `0x40 = 0x6 * 0xA + 0x4`, so is actually `this->skelAnime.jointTable[10].z`
Lastly, what is `globalCtx->unk1D94`? It is at `globalCtx->csCtx + 0x30`, or `globalCtx->csCtx.npcActions + 0x8`, which is `globalCtx->csCtx.npcActions[2]` since this is an array of pointers. Hence it is a pointer, and so should be compared to `NULL`. Looking up the sfx Id again, we end up with
```C
void EnJj_Update(Actor *thisx, GlobalContext *globalCtx) {
EnJj* this = THIS;
if ((globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->csCtx.npcActions[2] != NULL)) {
func_80A87D94(this, globalCtx);
} else {
this->actionFunc(this, globalCtx);
if (this->skelAnime.curFrame == 41.0f) {
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_JABJAB_GROAN);
}
}
func_80A87B1C(this);
SkelAnime_Update(&this->skelAnime);
Actor_SetScale(&this->dyna.actor, 0.087f);
this->skelAnime.jointTable[10].z = this->unk_308;
}
```
which matches.
3 more functions to go: the two functions called here, and Draw.
## `func_80A87B1C`
Now our typing problems come home to roost:
```C
void func_80A87B1C(EnJj *this) {
s8 temp_t8;
u8 temp_v0;
u8 temp_v0_2;
temp_v0 = (u8) this->unk_30F;
if ((s32) temp_v0 > 0) {
this->unk_30F = temp_v0 - 1;
return;
}
temp_t8 = (u8) this->unk_30E + 1;
this->unk_30E = temp_t8;
if ((temp_t8 & 0xFF) >= 3) {
temp_v0_2 = (u8) this->unk_310;
this->unk_30E = 0;
if ((s32) temp_v0_2 > 0) {
this->unk_310 = temp_v0_2 - 1;
return;
}
this = this;
this->unk_30F = Rand_S16Offset((u16)0x14, (u16)0x14);
this->unk_310 = (s8) (u8) this->unk_311;
}
}
```
From this we can read off that `unk_30F` is a `u8`, `unk_30E` is a `u8`, `unk_310` is a `u8`, and `unk_311` is a `u8`. Giving mips2c new context and trying again,
```C
void func_80A87B1C(EnJj *this) {
u8 temp_t8;
u8 temp_v0;
u8 temp_v0_2;
temp_v0 = this->unk_30F;
if ((s32) temp_v0 > 0) {
this->unk_30F = temp_v0 - 1;
return;
}
temp_t8 = this->unk_30E + 1;
this->unk_30E = temp_t8;
if ((temp_t8 & 0xFF) >= 3) {
temp_v0_2 = this->unk_310;
this->unk_30E = 0;
if ((s32) temp_v0_2 > 0) {
this->unk_310 = temp_v0_2 - 1;
return;
}
this = this;
this->unk_30F = Rand_S16Offset((u16)0x14, (u16)0x14);
this->unk_310 = this->unk_311;
}
}
```
and all the weird casts are gone. Eliminating the temps, replacing the hex, discarding pointless definitions, and replacing early `return`s by `else`s, we end up with
```C
void func_80A87B1C(EnJj* this) {
if (this->unk_30F > 0) {
this->unk_30F--;
} else {
this->unk_30E++;
if ((this->unk_30E & 0xFF) >= 3) {
this->unk_30E = 0;
if (this->unk_310 > 0) {
this->unk_310--;
} else {
this->unk_30F = Rand_S16Offset(20, 20);
this->unk_310 = this->unk_311;
}
}
}
}
```
Sadly this doesn't match:
![func_80A87B1C diff 1](images/func_80A87B1C_diff1.png)
You will also find that the permuter is essentially useless here: most solutions it offers look very fake. But there's already something a bit weird in here: why does it do `this->unk_30E & 0xFF` explicitly in the comparison? It turns out if you remove this, the function matches: the compiler does this calculation automatically when doing comparisons with `u8`s anyway.
![func_80A87B1C diff 2](images/func_80A87B1C_diff2.png)
### `func_80A87D94`
This is our last ordinary function. Unfortunately, even with new context, mips2c gives us a bit of a mess:
```C
void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
s16 temp_v0_2;
u16 temp_t1;
u16 temp_t4;
u16 temp_t7;
u16 temp_t9;
u16 temp_v0;
u16 temp_v1;
u16 temp_v1_2;
u16 temp_v1_3;
u16 phi_v1;
temp_v0 = *globalCtx->unk1D94;
if (temp_v0 != 1) {
if (temp_v0 != 2) {
if (temp_v0 != 3) {
phi_v1 = this->unk_30A;
} else {
temp_v1 = this->unk_30A;
temp_t7 = temp_v1 | 2;
phi_v1 = temp_v1;
if ((temp_v1 & 2) == 0) {
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 1;
this->unk_311 = 0;
this->unk_30A = temp_t7;
phi_v1 = temp_t7 & 0xFFFF;
}
}
} else {
temp_t1 = this->unk_30A | 1;
temp_v1_2 = temp_t1 & 0xFFFF;
this->unk_30A = temp_t1;
phi_v1 = temp_v1_2;
if ((temp_v1_2 & 8) == 0) {
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, (Actor *) this, globalCtx, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
temp_t4 = this->unk_30A | 8;
this->unk_30A = temp_t4;
phi_v1 = temp_t4 & 0xFFFF;
}
}
} else {
temp_v1_3 = this->unk_30A;
phi_v1 = temp_v1_3;
if ((temp_v1_3 & 2) != 0) {
this->unk_30E = 0;
this->unk_30F = Rand_S16Offset((u16)0x14, (u16)0x14);
this->unk_310 = 0;
temp_t9 = this->unk_30A ^ 2;
this->unk_311 = 0;
this->unk_30A = temp_t9;
phi_v1 = temp_t9 & 0xFFFF;
}
}
if ((phi_v1 & 1) != 0) {
Audio_PlayActorSound2((Actor *) this, (u16)0x206DU);
temp_v0_2 = this->unk_308;
if ((s32) temp_v0_2 >= -0x1450) {
this->unk_308 = temp_v0_2 - 0x66;
}
}
}
```
At the top we have
```C
temp_v0 = *globalCtx->unk1D94;
if (temp_v0 != 1) {
if (temp_v0 != 2) {
if (temp_v0 != 3) {
```
Firstly, we are now comparing with the value of `globalCtx->unk1D94`, not just using a pointer, so we need the first thing in `globalCtx->csCtx.npcActions[2]`. This turns out to be `globalCtx->csCtx.npcActions[2]->action`.
The if structure here is another classic indicator of a switch: nested, with the same variable compared multiple times. If you were to diff this as-is, you would find that the code is in completely the wrong order. Reading how the ifs work, we see that if `temp_v0` is `1`, it executes the outermost else block, if it is `2`, the middle, if `3`, the innermost, and if it is anything else, the contents of the innermost if. Hence this becomes
```C
void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
s16 temp_v0_2;
u16 temp_t1;
u16 temp_t4;
u16 temp_t7;
u16 temp_t9;
// u16 temp_v0;
u16 temp_v1;
u16 temp_v1_2;
u16 temp_v1_3;
u16 phi_v1;
switch (globalCtx->csCtx.npcActions[2]->action) {
case 1:
temp_v1_3 = this->unk_30A;
phi_v1 = temp_v1_3;
if ((temp_v1_3 & 2) != 0) {
this->unk_30E = 0;
this->unk_30F = Rand_S16Offset((u16)0x14, (u16)0x14);
this->unk_310 = 0;
temp_t9 = this->unk_30A ^ 2;
this->unk_311 = 0;
this->unk_30A = temp_t9;
phi_v1 = temp_t9 & 0xFFFF;
}
break;
case 2:
temp_t1 = this->unk_30A | 1;
temp_v1_2 = temp_t1 & 0xFFFF;
this->unk_30A = temp_t1;
phi_v1 = temp_v1_2;
if ((temp_v1_2 & 8) == 0) {
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, (Actor *) this, globalCtx, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
temp_t4 = this->unk_30A | 8;
this->unk_30A = temp_t4;
phi_v1 = temp_t4 & 0xFFFF;
}
break;
case 3:
temp_v1 = this->unk_30A;
temp_t7 = temp_v1 | 2;
phi_v1 = temp_v1;
if ((temp_v1 & 2) == 0) {
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 1;
this->unk_311 = 0;
this->unk_30A = temp_t7;
phi_v1 = temp_t7 & 0xFFFF;
}
break;
default:
phi_v1 = this->unk_30A;
break;
}
if ((phi_v1 & 1) != 0) {
Audio_PlayActorSound2((Actor *) this, (u16)0x206DU);
temp_v0_2 = this->unk_308;
if ((s32) temp_v0_2 >= -0x1450) {
this->unk_308 = temp_v0_2 - 0x66;
}
}
}
```
(notice that this time we need a `default` to deal with the innermost if contents). If you try to replace `0x206D` in the `Audio_PlayActorSound2`, you will find there is no such sfxId in the list: this is because some sound effects have an extra offset of `0x800` to do with setting flags. Adding `0x800` to the sfxId shows that this sound effect is `NA_SE_EV_JABJAB_BREATHE`. To correct this to the id in the function, we have a macro `SFX_FLAG`, and it should therefore be
```C
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_JABJAB_BREATHE - SFX_FLAG);
```
As usual, most of the remaining temps look fake. The only one that does not is possibly `phi_v1`. However, the way in which they are used here makes it hard to tell if they are fake, and if so, how to replace them. I encourage you to try this yourself, with the aid of the diff script; the final, matching result, with other cleanup, is hidden below
<details>
<summary>
Matching C for `func_80A87D94`
</summary>
```C
void func_80A87D94(EnJj* this, GlobalContext* globalCtx) {
switch (globalCtx->csCtx.npcActions[2]->action) {
case 1:
if ((this->unk_30A & 2) != 0) {
this->unk_30E = 0;
this->unk_30F = Rand_S16Offset(20, 20);
this->unk_310 = 0;
this->unk_311 = 0;
this->unk_30A ^= 2;
}
break;
case 2:
this->unk_30A |= 1;
if ((this->unk_30A & 8) == 0) {
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EFF_DUST,
-1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
this->unk_30A |= 8;
}
break;
case 3:
if ((this->unk_30A & 2) == 0) {
this->unk_30E = 0;
this->unk_30F = 0;
this->unk_310 = 1;
this->unk_311 = 0;
this->unk_30A |= 2;
}
break;
}
if ((this->unk_30A & 1) != 0) {
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_JABJAB_BREATHE - SFX_FLAG);
if (this->unk_308 >= -5200) {
this->unk_308 -= 102;
}
}
}
```
</details>
With that, the last remaining function is `EnJj_Draw`. Draw functions have an extra layer of macroing that is required, so we shall cover them separately.
Next: [Draw functions](draw_functions.md)

View File

@ -1,31 +0,0 @@
# Pre-decompilation
It is very important to get everything set up properly before you start trying to decompile anything. As usual, if you need help at any stage of the process, ask in the Discord and we'll do our best to help.
## Setting up the repository
This is covered on the main page of the repository.
## Git and GitHub workflow
First, make a GitHub fork of the repository, then clone it into a git-enabled local folder.
Once you have decided on an actor, you should make a new git branch to work on: your master branch is meant to stay level with the main repository. Name it something sensible: my `EnFirefly` branch is called "en_firefly", for example, but you may prefer to use a more descriptive name: "Dark_Link" is rather more suggestive than "en_torch2", for example. You work on the branch, commit changes, and periodically push them to GitHub, if only for backup purposes.
Once you have finished an actor, you submit a pull request for other people to check your work complies with the project's conventions, and once it is deemed satisfactory, it will be merged in to the main repository.
But we are getting ahead of ourselves:
## Choosing a first actor
Since actors cover so many different categories of stuff in the game, they come in a wide variety of shapes, sizes and difficulties. The following is a list of things to bear in mind:
- Bosses are by far the largest, and all are already taken, so you can safely ignore them. Likewise `ovl_Fishing`, the largest actor in the game.
- Enemies are often quite complicated due to the many different interactions they have with Link, and sometimes one another.
- NPCs vary hugely. Some of the smaller ones are suitable to be first actors, but many are not.
- Cutscene objects tend to have very complicated functions, and are best left until later.
- The best starter actors tend to be dungeon or scene objects: statues, platforms, decorations, gates, etc., although we are naturally running a bit short on these now.
The general rule of thumb is to pick something with few, simple interactions with its environment. (For example, my first actor was BgIceTurara: icicles, which can do about 3 different things: break, fall, and grow.) This hopefully means that the functions are mostly small and simple. You are also probably better off if Draw and Init are small functions, although difficulty is sometimes not correlated to size.
If in doubt, ask someone to have a quick look through the code to see if it's suitable.

View File

@ -1,149 +0,0 @@
# Types, structs, and padding
Reminders:
- In N64 MIPS, 1 word is 4 bytes (yes, the N64 is meant to be 64-bit, but it mostly isn't used like it in OoT)
- A byte is 8 bits, or 2 hex digits
## Types
The following are the common data types used everywhere:
| Name | Size | Comment |
| ---- | ----- | -------- |
| char | 1 byte | character |
| u8 | 1 byte | unsigned byte |
| s8 | 1 byte | signed byte |
| u16 | 2 bytes | unsigned short |
| s16 | 2 bytes | signed short |
| u32 | 4 bytes/1 word | unsigned int |
| s32 | 4 bytes/1 word | signed int |
| void* | 4 bytes/1 word | pointer |
A pointer is sometimes mistaken for an s32. s32 is the default thing to use in the absence of any other information about the data.
Useful data for guessing types:
- u8 is about 7 times more common than s8 (so the tutorial is a bit misleading)
- s16 is about 16 times more common than u16
- s32 is about 8 times more common than u32
Another useful thing to put here: the prototype for an action function is
```C
typedef void (*ActorNameActionFunc)(struct ActorName*, GlobalContext*);
```
where you replace `ActorName` by the actual actor name as used elsewhere in the actor, e.g. `EnJj`.
## Some Common Structs
Here are the usual names and the sizes of some of the most common structs used in actors and their structs:
| Type | Usual name | Size |
| ----------------------- | --------------------- | --------------- |
| `Actor` | `actor` | 0x14C |
| `DynaPolyActor` | `dyna` | 0x164 |
| `Vec3f` | | 0xC |
| `Vec3s` | | 0x6 |
| `SkelAnime` | `skelAnime` | 0x44 |
| `Vec3s[limbCount]` | `jointTable` | 0x6 * limbCount |
| `Vec3s[limbCount]` | `morphTable` | 0x6 * limbCount |
| `ColliderCylinder` | `collider` | 0x4C |
| `ColliderQuad` | `collider` | 0x80 |
| `ColliderJntSph` | `collider` | 0x20 |
| `ColliderJntSphElement` | `colliderElements[n]` | 0x40 * n |
| `ColliderTris` | `collider` | 0x20 |
| `ColliderTrisElement` | `colliderElements[n]` | 0x5C * n |
(`colliderElements` used to be called `colliderItems`, and we have not switched over fully in the repo yet.)
## Padding
### Alignment
A stored variable or piece of data does not always start immediately after the previous one: there may be padding in between: `0`s that are never written or referred to, and so ignored. This is to do with how the processor accesses memory: it reads 1 word at a time, so multibyte objects are aligned so they cross as few word boundaries as possible.
The clearest example of this is that variables with types that are 1 word in size (`s32`s and pointers, for example) are automatically shifted so that they start at the beginning of the next word, i.e. at an offset ending with one of `0,4,8,C`: this is called 4-alignment. This will also happen to `s16`s, but with 2-alignment
### Struct padding
In actor structs, this manifests as some of the char arrays not being completely replaced by actual variables. For example, BgIceTurara, the actor for icicles, has the following actor struct:
```C
typedef struct BgIceTurara {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0164 */ BgIceTuraraActionFunc actionFunc;
/* 0x0168 */ s16 shiverTimer;
/* 0x016C */ ColliderCylinder collider;
} BgIceTurara; // size = 0x01B8
```
Notice that even though `timer` is an `s16`, `collider` is at `this + 0x16C`: there was originally a `char unk_166[0x2]` left over from the original char array, but it has been removed without affecting the alignment.
How do structs themselves align? A struct has the same alignment properties as its longest constituent (that is not itself a struct). For example, a `Vec3f` has 4-alignment, while a `Vec3s` has 2-alignment.
A struct may also pad at the end: it will pad to the size of its largest non-struct element. Notably, every actor struct has size a whole number of words as well, so this phenomenon also occurs at the ends of structs: see, for example, EnJj's actor struct that we filled out in the tutorial: the `char unk_312[0x2]` is unnecessary, because it is used nowhere, and the struct pads to `0x314` anyway.
For more information on this topic, there are plenty of guides elsewhere on the Internet. *The main thing to bear in mind for decomp purposes is that after finishing the functions, there may be some small parts of the actor struct that are just not used, because they were originally just struct padding.*
### Padding at the end of sections
<!-- a file is made up of multiple sections
.text (instructions)
.data
.rodata (read only data, includes strings, floats, jumptables etc)
.bss (zero initialized variables, not assigned a value when declared)
.reloc (only relevant for overlays, used to reloc pointers when loaded dynamically)
each of these sections are 0x10/16 aligned, meaning the compiler will insert padding between each section to align them to an address that ends in 0
any new entry in .data must be 4 aligned no matter its size
(i forgot if rodata bss is 4 aligned for each new entry, should find that out)
additionally, if an object is split into multiple c files, you will see a 16 alignment in the different sections at the point of the file split -->
In the ROM, each actor is layed out in the following order:
- .text (Function instructions, separated into .s files, aka .text)
- .data (contents of the .data.s file)
- .rodata (read-only data, includes strings, floats, jumptables etc., moved to the appropriate function files in the OoT repo)
- .bss (varibles initialised to 0, not assigned a value when declared)
- .reloc (relocation information: you can ignore this)
Each section is 0x10/16-aligned (qword aligned): each new section begins at an address with last digit `0`. This means that there can occur up to three words of padding at the end of each section.
(The same occurs with any object divided into multiple .c files: each new file becomes 0x10 aligned.)
#### Padding at the end of .text (function instructions)
In function instructions, this manifests as a set of `nop`s at the end of the last function, and once the rest of the functions match, this is automatic. So you never need to worry about these.
#### Padding at the end of .data
In data, the last entry may contain up to 3 words of 0s as padding. These can safely be removed when migrating data, but make sure that you don't remove something that actually is accessed by the function and happens to be 0!
For example, in `EnJj` we found that the last symbol in the data,
```C
glabel D_80A88CFC
.word 0x06007698, 0x06007A98, 0x06007E98, 0x00000000, 0x00000000
```
had 2 words of padding: only the first 3 entries are actually used.
### Padding within the .data section
Every distinct symbol in data is 4-aligned (word-aligned). So in the data, even if you have two `u8`s, they will be stored in addresses starting successive words:
```C
u8 byte1 = 1 // will go to address ending in 0
u8 byte2 = 2 // Will go to address ending in 4
```
#### Fake symbols
The process of separating the data is not flawless, and sometimes gives rise to symbols that are fake: that is, containing data that should not be stored by itself, but part of a different earlier symbol.
Since `D_address` corresponds to the address where the symbol is stored, every address should be word-aligned, i.e. end in one of `0,4,8,C`. Any symbols that do not are fake, and the data attached to them should be joined to the data of previous symbol, with all references to them adjusted to the correct offset from the previous symbol.
Thankfully most of the fake symbols have now been automatically eliminated, but that does not mean that there are none left. Symbols can also be fake if they have the correct alignment, but are rather harder to spot.

View File

@ -1,30 +0,0 @@
# VSCode
A lot of people on this project use VSCode as their coding environment, and there are a number of useful plugins available to make work more efficient:
- c/c++ intellisense
- clang-format
- hexinspector (hover on numbers for float and other info)
- numbermonger (hex to decimal and vice versa)
- bracket pair colorizer 2
- better mips support
You will probably also find it helpful to watch Fig's video, although it was not meant to be an actual introduction. But it does show various useful features of VSCode, quite apart from the decompilation aspect.
Useful stuff to know:
- Ctrl + Alt + Up/Down (on Windows, on Linux it's Ctrl + Shift + Up/Down or Shift + Alt + Up/Down) gives multicursors across consecutive lines. If you want several cursors in a more diverse arrangement, middle clicking works, at least on Windows.
- Alt + Up/Down moves lines up/down.
- Shift + Alt + Up/Down (Linux: Ctrl + Shift + Alt + Up/Down) copies lines up/down.
- Make use of VSCode's search/search-and-replace features.
- Ctrl + Click goes to a definition.
- Ctrl + F for search in current file
- Ctrl + H for replace in current file
- Ctrl + Shift + F for search in all files
- Ctrl + Shift + H for replace in all files
- F2 for Rename symbol
Many of VS Code's other shortcuts can be found on [its getting started page](https://code.visualstudio.com/docs/getstarted/keybindings), which also has links to OS-specific PDFs.

View File

@ -1,255 +0,0 @@
#!/usr/bin/env python3
import os.path
import argparse
from subprocess import check_call
parser = argparse.ArgumentParser(
description="Find the first difference(s) between the built ROM and the base ROM."
)
parser.add_argument(
"-c",
"--count",
type=int,
default=5,
help="find up to this many instruction difference(s)",
)
parser.add_argument(
"-d",
"--diff",
dest="diff_args",
nargs="?",
action="store",
default=False,
const="prompt",
help="run diff.py on the result with the provided arguments"
)
parser.add_argument(
"-m", "--make", help="run make before finding difference(s)", action="store_true"
)
args = parser.parse_args()
diff_count = args.count
if args.make:
check_call(["make", "-j4", "COMPARE=0"])
baseimg = f"baserom.z64"
basemap = f"expected/build/z64.map"
myimg = f"zelda_ocarina_mq_dbg.z64"
mymap = f"build/z64.map"
if not os.path.isfile(baseimg):
print(f"{baseimg} must exist.")
exit(1)
if not os.path.isfile(myimg) or not os.path.isfile(mymap):
print(f"{myimg} and {mymap} must exist.")
exit(1)
mybin = open(myimg, "rb").read()
basebin = open(baseimg, "rb").read()
if len(mybin) != len(basebin):
print("Modified ROM has different size...")
exit(1)
if mybin == basebin:
print("No differences!")
exit(0)
def search_rom_address(target_addr):
ram_offset = None
prev_ram = 0
prev_rom = 0
prev_sym = "<start of rom>"
cur_file = "<no file>"
prev_file = cur_file
prev_line = ""
with open(mymap) as f:
for line in f:
if "load address" in line:
# Ignore .bss sections since we're looking for a ROM address
if ".bss" in line or ".bss" in prev_line:
ram_offset = None
continue
ram = int(line[16 : 16 + 18], 0)
rom = int(line[59 : 59 + 18], 0)
ram_offset = ram - rom
continue
prev_line = line
if (
ram_offset is None
or "=" in line
or "*fill*" in line
or " 0x" not in line
):
continue
ram = int(line[16 : 16 + 18], 0)
rom = ram - ram_offset
sym = line.split()[-1]
if sym.startswith("0x"):
ram_offset = None
continue
if "/" in sym:
cur_file = sym
continue
if rom > target_addr:
return f"{prev_sym} (RAM 0x{prev_ram:X}, ROM 0x{prev_rom:X}, {prev_file})"
prev_ram = ram
prev_rom = rom
prev_sym = sym
prev_file = cur_file
return "at end of rom?"
def parse_map(map_fname):
ram_offset = None
cur_file = "<no file>"
syms = {}
prev_sym = None
prev_line = ""
with open(map_fname) as f:
for line in f:
if "load address" in line:
ram = int(line[16 : 16 + 18], 0)
rom = int(line[59 : 59 + 18], 0)
ram_offset = ram - rom
continue
prev_line = line
if (
ram_offset is None
or "=" in line
or "*fill*" in line
or " 0x" not in line
):
continue
ram = int(line[16 : 16 + 18], 0)
rom = ram - ram_offset
sym = line.split()[-1]
if sym.startswith("0x"):
ram_offset = None
continue
elif "/" in sym:
cur_file = sym
continue
syms[sym] = (rom, cur_file, prev_sym, ram)
prev_sym = sym
return syms
def map_diff():
map1 = parse_map(mymap)
map2 = parse_map(basemap)
min_ram = None
found = None
for sym, addr in map1.items():
if sym not in map2:
continue
if addr[0] != map2[sym][0]:
if min_ram is None or addr[0] < min_ram:
min_ram = addr[0]
found = (sym, addr[1], addr[2])
if min_ram is None:
return False
else:
print(
f"Map appears to have shifted just before {found[0]} ({found[1]}) -- in {found[2]}?"
)
if found[2] is not None and found[2] not in map2:
print(
f"(Base map file {basemap} out of date due to new or renamed symbols, so result may be imprecise.)"
)
return True
def hexbytes(bs):
return ":".join("{:02X}".format(c) for c in bs)
found_instr_diff = []
map_search_diff = []
diffs = 0
shift_cap = 1000
for i in range(24, len(mybin), 4):
# (mybin[i:i+4] != basebin[i:i+4], but that's slightly slower in CPython...)
if diffs <= shift_cap and (
mybin[i] != basebin[i]
or mybin[i + 1] != basebin[i + 1]
or mybin[i + 2] != basebin[i + 2]
or mybin[i + 3] != basebin[i + 3]
):
if diffs == 0:
print(f"First difference at ROM addr 0x{i:X}, {search_rom_address(i)}")
print(
f"Bytes: {hexbytes(mybin[i : i + 4])} vs {hexbytes(basebin[i : i + 4])}"
)
diffs += 1
if (
len(found_instr_diff) < diff_count
and mybin[i] >> 2 != basebin[i] >> 2
and not search_rom_address(i) in map_search_diff
):
found_instr_diff.append(i)
map_search_diff.append(search_rom_address(i))
if diffs == 0:
print("No differences but ROMs differ?")
exit()
if len(found_instr_diff) > 0:
for i in found_instr_diff:
print(f"Instruction difference at ROM addr 0x{i:X}, {search_rom_address(i)}")
print(
f"Bytes: {hexbytes(mybin[i : i + 4])} vs {hexbytes(basebin[i : i + 4])}"
)
print()
definite_shift = diffs > shift_cap
if definite_shift:
print(f"Over {shift_cap} differing words, must be a shifted ROM.")
else:
print(f"{diffs} differing word(s).")
if diffs > 100:
if not os.path.isfile(basemap):
print(
f"To find ROM shifts, copy a clean .map file to {basemap} and rerun this script."
)
elif not map_diff():
print(f"No ROM shift{' (!?)' if definite_shift else ''}")
if args.diff_args:
if len(found_instr_diff) < 1:
print(f"No instruction difference to run diff.py on")
exit()
diff_sym = search_rom_address(found_instr_diff[0]).split()[0]
if args.diff_args == "prompt":
diff_args = input("Call diff.py with which arguments? ") or "--"
else:
diff_args = args.diff_args
if diff_args[0] != "-":
diff_args = "-" + diff_args
check_call(
[
"python3",
"diff.py",
diff_args,
diff_sym,
]
)

2132
oldfuncs.h

File diff suppressed because it is too large Load Diff

10470
spec

File diff suppressed because it is too large Load Diff

View File

@ -1,139 +0,0 @@
#!/usr/bin/env python3
import os.path
import argparse
parser = argparse.ArgumentParser(
description="Display various information about a symbol or address."
)
parser.add_argument(
"name",
type=str,
default="",
help="symbol name or ROM/RAM address to lookup"
)
parser.add_argument(
"-e",
"--expected",
dest="use_expected",
action="store_true",
help="use the map file in expected/build/ instead of build/"
)
args = parser.parse_args()
mymap = "build/z64.map"
if args.use_expected:
mymap = f"expected/{mymap}"
if not os.path.isfile(mymap):
print(f"{mymap} must exist.")
exit(1)
def search_address(target_addr):
is_ram = target_addr & 0x80000000
ram_offset = None
prev_ram = 0
prev_rom = 0
prev_sym = "<start of rom>"
cur_file = "<no file>"
prev_file = cur_file
prev_line = ""
with open(mymap) as f:
for line in f:
if "load address" in line:
# Ignore .bss sections if we're looking for a ROM address
if not is_ram and (".bss" in line or ".bss" in prev_line):
ram_offset = None
continue
ram = int(line[16 : 16 + 18], 0)
rom = int(line[59 : 59 + 18], 0)
ram_offset = ram - rom
continue
prev_line = line
if (
ram_offset is None
or "=" in line
or "*fill*" in line
or " 0x" not in line
):
continue
ram = int(line[16 : 16 + 18], 0)
rom = ram - ram_offset
sym = line.split()[-1]
if sym.startswith("0x"):
ram_offset = None
continue
if "/" in sym:
cur_file = sym
continue
if rom == target_addr or (is_ram and ram == target_addr):
return f"{sym} (RAM 0x{ram:X}, ROM 0x{rom:X}, {cur_file})"
if rom > target_addr or (is_ram and ram > target_addr):
offset = target_addr - prev_ram if is_ram else target_addr - prev_rom
return f"at 0x{offset:X} bytes inside {prev_sym} (RAM 0x{prev_ram:X}, ROM 0x{prev_rom:X}, {prev_file})"
prev_ram = ram
prev_rom = rom
prev_sym = sym
prev_file = cur_file
return "at end of rom?"
def search_symbol(target_sym):
ram_offset = None
cur_file = "<no file>"
prev_line = ""
with open(mymap) as f:
for line in f:
if "load address" in line:
ram = int(line[16 : 16 + 18], 0)
rom = int(line[59 : 59 + 18], 0)
ram_offset = ram - rom
continue
prev_line = line
if (
ram_offset is None
or "=" in line
or "*fill*" in line
or " 0x" not in line
):
continue
ram = int(line[16 : 16 + 18], 0)
rom = ram - ram_offset
sym = line.split()[-1]
if sym.startswith("0x"):
ram_offset = None
continue
elif "/" in sym:
cur_file = sym
continue
if sym == target_sym:
return (rom, cur_file, ram)
return None
try:
target_addr = int(args.name, 0)
print(args.name, "is", search_address(target_addr))
except ValueError:
sym_info = search_symbol(args.name)
if sym_info is not None:
sym_rom = sym_info[0]
sym_file = sym_info[1]
sym_ram = sym_info[2]
print(f"Symbol {args.name} (RAM: 0x{sym_ram:08X}, ROM: 0x{sym_rom:06X}, {sym_file})")
else:
print(f"Symbol {args.name} not found in map file {mymap}")

View File

@ -1,74 +0,0 @@
// libultra OS symbols
osTvType = 0x80000300;
osRomBase = 0x80000308;
osResetType = 0x8000030C;
osMemSize = 0x80000318;
osAppNmiBuffer = 0x8000031C;
// OS hardware registers
D_A4040004 = 0xA4040004;
D_A4040008 = 0xA4040008;
D_A404000C = 0xA404000C;
D_A4040010 = 0xA4040010;
D_A4300008 = 0xA4300008;
D_A430000C = 0xA430000C;
D_A4400004 = 0xA4400004;
D_A4400008 = 0xA4400008;
D_A440000C = 0xA440000C;
D_A4400010 = 0xA4400010;
D_A4400014 = 0xA4400014;
D_A4400018 = 0xA4400018;
D_A440001C = 0xA440001C;
D_A4400020 = 0xA4400020;
D_A4400024 = 0xA4400024;
D_A4400028 = 0xA4400028;
D_A440002C = 0xA440002C;
D_A4400030 = 0xA4400030;
D_A4400034 = 0xA4400034;
D_A4500004 = 0xA4500004;
D_A4500008 = 0xA4500008;
D_A450000C = 0xA450000C;
D_A4500010 = 0xA4500010;
D_A4500014 = 0xA4500014;
D_A4600004 = 0xA4600004;
D_A4600005 = 0xA4600005;
D_A4600006 = 0xA4600006;
D_A4600007 = 0xA4600007;
D_A4600008 = 0xA4600008;
D_A460000C = 0xA460000C;
D_A4600010 = 0xA4600010;
D_A4600014 = 0xA4600014;
D_A4600018 = 0xA4600018;
D_A460001C = 0xA460001C;
D_A4600020 = 0xA4600020;
D_A4600024 = 0xA4600024;
D_A4600028 = 0xA4600028;
D_A460002C = 0xA460002C;
D_A4600030 = 0xA4600030;
D_A4800000 = 0xA4800000; // SI_DRAM_ADDR_REG
D_A4800004 = 0xA4800004; // SI_PIF_ADDR_RD64B_REG
D_A4800010 = 0xA4800010; // SI_PIF_ADDR_WR64B_REG
D_A4800018 = 0xA4800018; // SI_STATUS_REG
// until ZAPD can handle non-aligned textures,
// we can't use the built assets tied to some symbols
gKm1Skel = 0x060000F0;
gKw1Skel = 0x060000F0;
object_ahg_Skel_0000F0 = 0x060000F0;
object_bji_Skel_0000F0 = 0x060000F0;
object_boj_Skel_0000F0 = 0x060000F0;
// z_kankyo, z_demo_kankyo, z_en_viewer, z_object_kankyo, z_eff_ss_dead_dd
D_01000000 = 0x01000000;
// code_800AD920
D_0E000000 = 0x0E000000;
// z_vismono
D_0F000000 = 0x0F000000;
// z_en_a_keep or en_a_obj
D_06000730 = 0x06000730;
// z_bg_mjin
D_06000000 = 0x06000000;

View File

@ -1,225 +0,0 @@
extern Mtx D_01000000;
extern u32 osTvType;
extern u32 osRomBase;
extern u32 osResetType;
extern u32 osMemSize;
extern u8 osAppNmiBuffer[0x40];
extern u8 D_80009320[];
extern u8 D_800093F0[];
extern s8 D_80009430;
extern u32 D_80009460;
extern u32 gDmaMgrDmaBuffSize;
extern vu8 gViConfigUseDefault;
extern u8 gViConfigAdditionalScanLines;
extern u32 gViConfigFeatures;
extern void* gItemIconsCurrent[86];
extern f32 gViConfigXScale;
extern void* gItemIconsGray[86][32*32];
extern f32 gViConfigYScale;
extern OSPiHandle* gCartHandle;
extern u32 __osPiAccessQueueEnabled;
extern OSViMode osViModePalLan1;
extern s32 osViClock;
extern u32 __osShutdown;
extern OSHWIntr __OSGlobalIntMask;
extern OSThread* __osThreadTail[];
extern OSThread* __osRunQueue;
extern OSThread* __osActiveQueue;
extern OSThread* __osRunningThread;
extern OSThread* __osFaultedThread;
extern OSPiHandle* __osPiTable;
extern OSPiHandle* __osCurrentHandle[];
extern OSTimer* __osTimerList;
extern OSViMode osViModeNtscLan1;
extern OSViMode osViModeMpalLan1;
extern OSViContext* __osViCurr;
extern OSViContext* __osViNext;
extern OSViMode osViModeFpalLan1;
extern u32 __additional_scanline;
extern u8 gBuildTeam[];
extern u8 gBuildDate[];
extern u8 gBuildMakeOption[];
extern OSMesgQueue gPiMgrCmdQ;
extern OSViMode gViConfigMode;
extern u8 D_80013960;
extern OSMesgQueue __osPiAccessQueue;
extern OSPiHandle __Dom1SpeedParam;
extern OSPiHandle __Dom2SpeedParam;
extern OSTime __osCurrentTime;
extern u32 __osBaseCounter;
extern u32 __osViIntrCount;
extern u32 __osTimerCounter;
extern DmaEntry gDmaDataTable[0x60C];
extern u64 D_801120C0[];
extern u8 D_80113070[];
extern u64 gJpegUCode[];
extern EffectSsOverlay gEffectSsOverlayTable[EFFECT_SS_TYPE_MAX];
extern Gfx D_80116280[];
extern ActorOverlay gActorOverlayTable[ACTOR_ID_MAX];
extern s32 gMaxActorId;
extern s32 gDbgCamEnabled;
extern GameStateOverlay gGameStateOverlayTable[6];
extern u8 gWeatherMode;
extern u8 D_8011FB34;
extern u8 D_8011FB38;
extern u8 gSkyboxBlendingEnabled;
extern u16 gTimeIncrement;
extern struct_8011FC1C D_8011FC1C[][9];
extern SkyboxFile gSkyboxFiles[];
extern s32 gZeldaArenaLogSeverity;
extern MapData gMapDataTable;
extern s16 gSpoilingItems[3];
extern s16 gSpoilingItemReverts[3];
extern FlexSkeletonHeader* gPlayerSkelHeaders[2];
extern u8 gPlayerModelTypes[][5];
extern Gfx* D_80125DE8[];
extern Gfx* D_80125E08[];
extern Gfx* D_80125E18[];
extern Gfx* D_80125EF8[];
extern Gfx gCullBackDList[];
extern Gfx gCullFrontDList[];
extern Gfx gEmptyDL[];
extern u32 gBitFlags[32];
extern u16 gEquipMasks[4];
extern u16 gEquipNegMasks[4];
extern u32 gUpgradeMasks[8];
extern u8 gEquipShifts[4];
extern u8 gUpgradeShifts[8];
extern u16 gUpgradeCapacities[8][4];
extern u32 gGsFlagsMasks[4];
extern u32 gGsFlagsShifts[4];
extern void* gItemIcons[0x82];
extern u8 gItemSlots[56];
extern void (*gSceneCmdHandlers[26])(GlobalContext*, SceneCmd*);
extern s16 gLinkObjectIds[2];
extern u32 gObjectTableSize;
extern RomFile gObjectTable[OBJECT_ID_MAX];
extern EntranceInfo gEntranceTable[1556];
extern SceneTableEntry gSceneTable[SCENE_ID_MAX];
extern u16 gSramSlotOffsets[];
extern u64 gMojiFontTLUTs[4][4];
extern u64 gMojiFontTex[];
extern KaleidoMgrOverlay gKaleidoMgrOverlayTable[KALEIDO_OVL_MAX];
extern KaleidoMgrOverlay* gKaleidoMgrCurOvl;
extern u8 gBossMarkState;
extern void* D_8012D1F0;
extern s32 gScreenWidth;
extern s32 gScreenHeight;
extern Mtx gMtxClear;
extern MtxF gMtxFClear;
extern u32 gIsCtrlr2Valid;
extern vu32 gIrqMgrResetStatus;
extern volatile OSTime gIrqMgrRetraceTime;
extern s16* gWaveSamples[9];
extern f32 gBendPitchOneOctaveFrequencies[256];
extern f32 gBendPitchTwoSemitonesFrequencies[256];
extern f32 gNoteFrequencies[];
extern u8 gDefaultShortNoteVelocityTable[16];
extern u8 gDefaultShortNoteGateTimeTable[16];
extern AdsrEnvelope gDefaultEnvelope[4];
extern NoteSubEu gZeroNoteSub;
extern NoteSubEu gDefaultNoteSub;
extern u16 gHeadsetPanQuantization[64];
extern s16 D_8012FBA8[];
extern f32 gHeadsetPanVolume[128];
extern f32 gStereoPanVolume[128];
extern f32 gDefaultPanVolume[128];
extern s16 sLowPassFilterData[16*8];
extern s16 sHighPassFilterData[15*8];
extern s32 gAudioContextInitalized;
extern u8 gIsLargeSoundBank[7];
extern u8 gChannelsPerBank[4][7];
extern u8 gUsedChannelsPerBank[4][7];
extern u8 gMorphaTransposeTable[16];
extern u8* gFrogsSongPtr;
extern OcarinaNote* gScarecrowCustomSongPtr;
extern u8* gScarecrowSpawnSongPtr;
extern OcarinaSongInfo gOcarinaSongNotes[];
extern SoundParams* gSoundParams[7];
extern char D_80133390[];
extern char D_80133398[];
extern SoundBankEntry* gSoundBanks[7];
extern u8 gSfxChannelLayout;
extern Vec3f D_801333D4;
extern f32 D_801333E0;
extern s8 D_801333E8;
extern u8 D_801333F0;
extern u8 gAudioSfxSwapOff;
extern u8 D_80133408;
extern u8 D_8013340C;
extern u8 gAudioSpecId;
extern u8 D_80133418;
extern AudioSpec gAudioSpecs[18];
extern s32 gOverlayLogSeverity;
extern s32 gSystemArenaLogSeverity;
extern u8 __osPfsInodeCacheBank;
extern s32 __osPfsLastChannel;
extern const s16 D_8014A6C0[];
extern AudioContextInitSizes D_8014A6C4;
extern s16 gOcarinaSongItemMap[];
extern u8 gSoundFontTable[];
extern u8 gSequenceFontTable[];
extern u8 gSequenceTable[];
extern u8 gSampleBankTable[];
extern u8 D_80155F50[];
extern u8 D_80157580[];
extern u8 D_801579A0[];
extern u64 gJpegUCodeData[];
extern SaveContext gSaveContext;
extern GameInfo* gGameInfo;
extern u16 D_8015FCC0;
extern u16 D_8015FCC2;
extern u16 D_8015FCC4;
extern u8 D_8015FCC8;
extern u8 gCustomLensFlareOn;
extern Vec3f gCustomLensFlarePos;
extern s16 gLensFlareScale;
extern f32 gLensFlareColorIntensity;
extern s16 gLensFlareScreenFillAlpha;
extern LightningStrike gLightningStrike;
extern MapData* gMapData;
extern f32 gBossMarkScale;
extern PauseMapMarksData* gLoadedPauseMarkDataTable;
extern s32 gTrnsnUnkState;
extern Color_RGBA8_u32 D_801614B0;
extern PreNmiBuff* gAppNmiBufferPtr;
extern SchedContext gSchedContext;
extern PadMgr gPadMgr;
extern u32 gSegments[NUM_SEGMENTS];
extern volatile OSTime D_8016A520;
extern volatile OSTime D_8016A528;
extern volatile OSTime D_8016A530;
extern volatile OSTime D_8016A538;
extern volatile OSTime D_8016A540;
extern volatile OSTime D_8016A548;
extern volatile OSTime D_8016A550;
extern volatile OSTime D_8016A558;
extern volatile OSTime gRSPAudioTotalTime;
extern volatile OSTime gRSPGFXTotalTime;
extern volatile OSTime gRSPOtherTotalTime;
extern volatile OSTime gRDPTotalTime;
extern FaultThreadStruct gFaultStruct;
extern ActiveSound gActiveSounds[7][MAX_CHANNELS_PER_BANK];
extern u8 gSoundBankMuted[];
extern u16 gAudioSfxSwapSource[10];
extern u16 gAudioSfxSwapTarget[10];
extern u8 gAudioSfxSwapMode[10];
extern u8 D_8016E348[4];
extern u32 sAudioSeqCmds[0x100];
extern unk_D_8016E750 D_8016E750[4];
extern AudioContext gAudioContext;
extern void(*D_801755D0)(void);
extern u32 __osMalloc_FreeBlockTest_Enable;
extern Arena gSystemArena;
extern OSPifRam __osPifInternalBuff;
extern u8 __osContLastPoll;
extern u8 __osMaxControllers;
extern __OSInode __osPfsInodeCache;
extern OSPifRam gPifMempakBuf;
extern u16 gZBuffer[SCREEN_HEIGHT][SCREEN_WIDTH];
extern u64 gGfxSPTaskOutputBuffer[0x3000];
extern u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE];
extern u8 gGfxSPTaskStack[0x400];
extern GfxPool gGfxPools[2];
extern u8 gAudioHeap[0x38000];
extern u8 gSystemHeap[];