Restructure build workflow

* All segments are now extracted from the base ROM; the base ROM is no
longer a compile time dependency
* ROM segments are now positioned relatively to each rather than with
hard coded addresses
* Piracy checksums are calculated during build
This commit is contained in:
Ryan Dwyer 2020-08-25 20:40:35 +10:00
parent 4fd334f73a
commit 23b6bd2643
34 changed files with 3239 additions and 2725 deletions

339
Makefile

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,6 @@ Before you do anything you need an existing ROM to extract assets from.
## Compiling
* Run `make` to build the assets that will be included in the ROM. These files will be written to `build/ntsc-final` and are matching what's in the `extracted/ntsc-final` folder.
* Run `make rom` to build the ROM. The ROM will be written to `build/ntsc-final/pd.z64`.
## How do I know the built files are matching?

View File

@ -2013,17 +2013,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/jap-final/files/bgdata/bg_uff_tilesZ
f0068491f441172310f2b6868c03739d build/jap-final/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/jap-final/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/jap-final/files/ob/ob_mid.seg
39ef58f5babf5d619bec8b2629c26bc8 build/jap-final/ucode/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/jap-final/ucode/firingrange.bin
bd6e5fc360d5e0c35ea3605e2514f205 build/jap-final/ucode/game.bin
22d5e92bffcc67b222cf3697e96106f6 build/jap-final/ucode/gamedata.bin
843285fdc0e80a77576eeb73940d2fd3 build/jap-final/ucode/inflate.bin
c550660ff4ba024113ddb38103bf79f8 build/jap-final/ucode/lib.bin
c47d9377956666bc0e77d6cba3dc68fb build/jap-final/ucode/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/jap-final/ucode/mpstringsE.bin
4d1eb9e58e090aa91301917c518b5b5f build/jap-final/ucode/mpstringsF.bin
0dfdacb249cb79aacb979509015fbab9 build/jap-final/ucode/mpstringsG.bin
3df64b3553f9d9b77f55e7abaccb8e04 build/jap-final/ucode/mpstringsI.bin
b60f7439adaf8b1e150ab54b590da411 build/jap-final/ucode/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/jap-final/ucode/mpstringsP.bin
9e9ad9fdc9b6a3c249a370760fa23b26 build/jap-final/ucode/mpstringsS.bin
538d2b75945eae069b29c46193e74790 build/jap-final/pd.z64
39ef58f5babf5d619bec8b2629c26bc8 build/jap-final/segments/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/jap-final/segments/firingrange.bin
bd6e5fc360d5e0c35ea3605e2514f205 build/jap-final/segments/game.bin
22d5e92bffcc67b222cf3697e96106f6 build/jap-final/segments/data.bin
843285fdc0e80a77576eeb73940d2fd3 build/jap-final/segments/inflate.bin
c550660ff4ba024113ddb38103bf79f8 build/jap-final/segments/lib.bin
c47d9377956666bc0e77d6cba3dc68fb build/jap-final/segments/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/jap-final/segments/mpstringsE.bin
4d1eb9e58e090aa91301917c518b5b5f build/jap-final/segments/mpstringsF.bin
0dfdacb249cb79aacb979509015fbab9 build/jap-final/segments/mpstringsG.bin
3df64b3553f9d9b77f55e7abaccb8e04 build/jap-final/segments/mpstringsI.bin
b60f7439adaf8b1e150ab54b590da411 build/jap-final/segments/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/jap-final/segments/mpstringsP.bin
9e9ad9fdc9b6a3c249a370760fa23b26 build/jap-final/segments/mpstringsS.bin

View File

@ -2011,17 +2011,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-1.0/files/bgdata/bg_uff_tilesZ
f0068491f441172310f2b6868c03739d build/ntsc-1.0/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-1.0/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/ntsc-1.0/files/ob/ob_mid.seg
402561223a33f48461e302e1cca12129 build/ntsc-1.0/ucode/boot.bin
cb373c94109322d081a57b142fdd9999 build/ntsc-1.0/ucode/firingrange.bin
5181a0d11cf8f24370a3f2d3b29e522e build/ntsc-1.0/ucode/game.bin
b21679a1b2dabd721bc4afee11bf5266 build/ntsc-1.0/ucode/gamedata.bin
843285fdc0e80a77576eeb73940d2fd3 build/ntsc-1.0/ucode/inflate.bin
3155eece856e9fbd9bc47d03463cfc1b build/ntsc-1.0/ucode/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/ntsc-1.0/ucode/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/ntsc-1.0/ucode/mpstringsE.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/ucode/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/ucode/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/ucode/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-1.0/ucode/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/ucode/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/ucode/mpstringsS.bin
7f4171b0c8d17815be37913f535e4e93 build/ntsc-1.0/pd.z64
402561223a33f48461e302e1cca12129 build/ntsc-1.0/segments/boot.bin
cb373c94109322d081a57b142fdd9999 build/ntsc-1.0/segments/firingrange.bin
5181a0d11cf8f24370a3f2d3b29e522e build/ntsc-1.0/segments/game.bin
b21679a1b2dabd721bc4afee11bf5266 build/ntsc-1.0/segments/data.bin
843285fdc0e80a77576eeb73940d2fd3 build/ntsc-1.0/segments/inflate.bin
3155eece856e9fbd9bc47d03463cfc1b build/ntsc-1.0/segments/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/ntsc-1.0/segments/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/ntsc-1.0/segments/mpstringsE.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/segments/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/segments/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/segments/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-1.0/segments/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/segments/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-1.0/segments/mpstringsS.bin

View File

@ -2010,17 +2010,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-beta/files/bgdata/bg_uff_tilesZ
c6f0dd6193685637763d426dfce837fb build/ntsc-beta/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-beta/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/ntsc-beta/files/ob/ob_mid.seg
74cb41628ed5784a8ad48c6398b0ce83 build/ntsc-beta/ucode/boot.bin
a12b5437510403bb09b3cceb45dd2a10 build/ntsc-beta/ucode/firingrange.bin
daae19f7ce11d3f3e1f98d543ad856f5 build/ntsc-beta/ucode/game.bin
cab47b8c30b1be608c1c5c1db08342de build/ntsc-beta/ucode/gamedata.bin
d13f25c1c59fb96346ac23301ccd9d7d build/ntsc-beta/ucode/inflate.bin
14aa42e2f0f215d931900d25ab70e576 build/ntsc-beta/ucode/lib.bin
8aaec8cc806ec62d2f70eaa08282e9c0 build/ntsc-beta/ucode/mpconfigs.bin
d52a0fc2e90e03b610879b50df4c0fd4 build/ntsc-beta/ucode/mpstringsE.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/ucode/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/ucode/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/ucode/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-beta/ucode/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/ucode/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/ucode/mpstringsS.bin
aa93f4df16fceada399a749f5ad2f273 build/ntsc-beta/pd.z64
74cb41628ed5784a8ad48c6398b0ce83 build/ntsc-beta/segments/boot.bin
a12b5437510403bb09b3cceb45dd2a10 build/ntsc-beta/segments/firingrange.bin
daae19f7ce11d3f3e1f98d543ad856f5 build/ntsc-beta/segments/game.bin
cab47b8c30b1be608c1c5c1db08342de build/ntsc-beta/segments/data.bin
d13f25c1c59fb96346ac23301ccd9d7d build/ntsc-beta/segments/inflate.bin
14aa42e2f0f215d931900d25ab70e576 build/ntsc-beta/segments/lib.bin
8aaec8cc806ec62d2f70eaa08282e9c0 build/ntsc-beta/segments/mpconfigs.bin
d52a0fc2e90e03b610879b50df4c0fd4 build/ntsc-beta/segments/mpstringsE.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/segments/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/segments/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/segments/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-beta/segments/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/segments/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-beta/segments/mpstringsS.bin

View File

@ -2011,17 +2011,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-final/files/bgdata/bg_uff_tilesZ
f0068491f441172310f2b6868c03739d build/ntsc-final/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/ntsc-final/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/ntsc-final/files/ob/ob_mid.seg
2a1aa1eff3cdfe5dc3e91a2e773a55b9 build/ntsc-final/ucode/boot.bin
cb373c94109322d081a57b142fdd9999 build/ntsc-final/ucode/firingrange.bin
ed0462324d1287de21611707172d316a build/ntsc-final/ucode/game.bin
11c9c4c2737f66e7312949909b894dcc build/ntsc-final/ucode/gamedata.bin
843285fdc0e80a77576eeb73940d2fd3 build/ntsc-final/ucode/inflate.bin
6a227624d708b43a10f220e005aef486 build/ntsc-final/ucode/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/ntsc-final/ucode/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/ntsc-final/ucode/mpstringsE.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-final/ucode/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/ucode/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/ucode/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/ucode/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/ucode/mpstringsI.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/ucode/mpstringsS.bin
e03b088b6ac9e0080440efed07c1e40f build/ntsc-final/pd.z64
2a1aa1eff3cdfe5dc3e91a2e773a55b9 build/ntsc-final/segments/boot.bin
cb373c94109322d081a57b142fdd9999 build/ntsc-final/segments/firingrange.bin
ed0462324d1287de21611707172d316a build/ntsc-final/segments/game.bin
11c9c4c2737f66e7312949909b894dcc build/ntsc-final/segments/data.bin
843285fdc0e80a77576eeb73940d2fd3 build/ntsc-final/segments/inflate.bin
6a227624d708b43a10f220e005aef486 build/ntsc-final/segments/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/ntsc-final/segments/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/ntsc-final/segments/mpstringsE.bin
302f7aa0464c781187551fcd3870aec2 build/ntsc-final/segments/mpstringsJ.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/segments/mpstringsP.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/segments/mpstringsF.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/segments/mpstringsG.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/segments/mpstringsI.bin
e4f45399a4f97e3fd6733f0f6919d28d build/ntsc-final/segments/mpstringsS.bin

View File

@ -2011,17 +2011,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/pal-beta/files/bgdata/bg_uff_tilesZ
f0068491f441172310f2b6868c03739d build/pal-beta/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/pal-beta/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/pal-beta/files/ob/ob_mid.seg
541e374b58a36056f73ad02a2bbb5f75 build/pal-beta/ucode/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/pal-beta/ucode/firingrange.bin
ad5835b91b7e252ef8f4a421a44eb12b build/pal-beta/ucode/game.bin
bca5001a5dd0ef9aab24ba085f27eb40 build/pal-beta/ucode/gamedata.bin
843285fdc0e80a77576eeb73940d2fd3 build/pal-beta/ucode/inflate.bin
7a859fcb6e89426543b5a207cc388f82 build/pal-beta/ucode/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/pal-beta/ucode/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/pal-beta/ucode/mpstringsE.bin
bed567631daf314f79ec8a2aa994f3a0 build/pal-beta/ucode/mpstringsF.bin
27be1b7f42826d0910b2fd549f969a63 build/pal-beta/ucode/mpstringsG.bin
fed3dc54a3564f477fb7d548ac365514 build/pal-beta/ucode/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/pal-beta/ucode/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/pal-beta/ucode/mpstringsP.bin
d9501d67ead982fdd5cb5ffaf3091201 build/pal-beta/ucode/mpstringsS.bin
ad2de210a3455ba5ec541f0c78d91444 build/pal-beta/pd.z64
541e374b58a36056f73ad02a2bbb5f75 build/pal-beta/segments/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/pal-beta/segments/firingrange.bin
ad5835b91b7e252ef8f4a421a44eb12b build/pal-beta/segments/game.bin
bca5001a5dd0ef9aab24ba085f27eb40 build/pal-beta/segments/data.bin
843285fdc0e80a77576eeb73940d2fd3 build/pal-beta/segments/inflate.bin
7a859fcb6e89426543b5a207cc388f82 build/pal-beta/segments/lib.bin
fe4034c01c91bd10e488fe93389b4104 build/pal-beta/segments/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/pal-beta/segments/mpstringsE.bin
bed567631daf314f79ec8a2aa994f3a0 build/pal-beta/segments/mpstringsF.bin
27be1b7f42826d0910b2fd549f969a63 build/pal-beta/segments/mpstringsG.bin
fed3dc54a3564f477fb7d548ac365514 build/pal-beta/segments/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/pal-beta/segments/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/pal-beta/segments/mpstringsP.bin
d9501d67ead982fdd5cb5ffaf3091201 build/pal-beta/segments/mpstringsS.bin

View File

@ -2011,17 +2011,18 @@ ea5a2ff4e5e0a68822f62feff2c40af4 build/pal-final/files/bgdata/bg_uff_tilesZ
f0068491f441172310f2b6868c03739d build/pal-final/files/bgdata/bg_wax_padsZ
ea5a2ff4e5e0a68822f62feff2c40af4 build/pal-final/files/bgdata/bg_wax_tilesZ
d41d8cd98f00b204e9800998ecf8427e build/pal-final/files/ob/ob_mid.seg
7c4233976802db99f90c6c0fede1080b build/pal-final/ucode/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/pal-final/ucode/firingrange.bin
4e506821044251aecc10ec332389c576 build/pal-final/ucode/game.bin
1c49c171e829a5407f0ae5fd28a123cd build/pal-final/ucode/gamedata.bin
843285fdc0e80a77576eeb73940d2fd3 build/pal-final/ucode/inflate.bin
b83973db626573e024608444e5d74461 build/pal-final/ucode/lib.bin
7f5540dd6fff2039b2ce05bf57ac5611 build/pal-final/ucode/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/pal-final/ucode/mpstringsE.bin
4d1eb9e58e090aa91301917c518b5b5f build/pal-final/ucode/mpstringsF.bin
0dfdacb249cb79aacb979509015fbab9 build/pal-final/ucode/mpstringsG.bin
3df64b3553f9d9b77f55e7abaccb8e04 build/pal-final/ucode/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/pal-final/ucode/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/pal-final/ucode/mpstringsP.bin
9e9ad9fdc9b6a3c249a370760fa23b26 build/pal-final/ucode/mpstringsS.bin
d9b5cd305d228424891ce38e71bc9213 build/pal-final/pd.z64
7c4233976802db99f90c6c0fede1080b build/pal-final/segments/boot.bin
333e8b4f6fe9dc9b59cf3e61b4e0c224 build/pal-final/segments/firingrange.bin
4e506821044251aecc10ec332389c576 build/pal-final/segments/game.bin
1c49c171e829a5407f0ae5fd28a123cd build/pal-final/segments/data.bin
843285fdc0e80a77576eeb73940d2fd3 build/pal-final/segments/inflate.bin
b83973db626573e024608444e5d74461 build/pal-final/segments/lib.bin
7f5540dd6fff2039b2ce05bf57ac5611 build/pal-final/segments/mpconfigs.bin
529b54a03375af2ff74eb3367cbac294 build/pal-final/segments/mpstringsE.bin
4d1eb9e58e090aa91301917c518b5b5f build/pal-final/segments/mpstringsF.bin
0dfdacb249cb79aacb979509015fbab9 build/pal-final/segments/mpstringsG.bin
3df64b3553f9d9b77f55e7abaccb8e04 build/pal-final/segments/mpstringsI.bin
302f7aa0464c781187551fcd3870aec2 build/pal-final/segments/mpstringsJ.bin
529b54a03375af2ff74eb3367cbac294 build/pal-final/segments/mpstringsP.bin
9e9ad9fdc9b6a3c249a370760fa23b26 build/pal-final/segments/mpstringsS.bin

File diff suppressed because it is too large Load Diff

458
ld/pd.ld
View File

@ -8,36 +8,57 @@
#define VERSION_PAL_FINAL 4
#define VERSION_JAP_FINAL 5
#define BEGIN_SEG(name) \
_##name##SegmentStart = ADDR(.name); \
_##name##SegmentRomStart = __rompos; \
.name __rampos : AT(__rompos)
#define END_SEG(name) \
__rompos += SIZEOF(.name); \
__rampos = ADDR(.name) + SIZEOF(.name); \
_##name##SegmentEnd = ADDR(.name) + SIZEOF(.name); \
_##name##SegmentRomEnd = __rompos;
#define BEGIN_NOLOAD(name) \
_##name##SegmentStart = ADDR(.name); \
_##name##SegmentRomStart = __rompos; \
.name (NOLOAD) : AT(__rompos)
#define END_NOLOAD(name) \
__rompos += SIZEOF(.name); \
_##name##SegmentEnd = ADDR(.name) + SIZEOF(.name); \
_##name##SegmentRomEnd = __rompos;
#define MPSTRINGS(lang) \
.mpstrings##lang : AT(__rompos) { \
BEGIN_SEG(mpstrings##lang) \
{ \
build/ROMID/mpstrings/ROMID/mpstrings##lang.o (.data); \
} \
__rompos += SIZEOF(.mpstrings##lang);
END_SEG(mpstrings##lang)
/******************************************************************************
* ROM Allocations
* ----------------------------------------------------------------------------
* The lib, data and game segments are compressed in the final ROM. To do this,
* we build them uncompressed here but place them past the end of the ROM, then
* a later script compresses them and writes them into the ROM.
*
* These constants are defining how much space is reserved for the compressed
* segments. If these segments are edited and grow to a point that their
* compressed size exceeds the allocation then their allocations will need to be
* increased.
*/
#define ROMALLOCATION_LIB 0x036800
#define ROMALLOCATION_DATA 0x015000
#define ROMALLOCATION_GAME 0x151980
#define ROMALLOCATION_FILES 0xe8dba0
OUTPUT_ARCH (mips)
SECTIONS
{
_gamedataSegmentStart = 0x80059fe0;
_gamedataSegmentRomStart = 0x39850;
_inflateSegmentRomStart = 0x4e850;
_ziplistSegmentRomStart = 0x4fc40;
_textureSegmentRomStart = 0x01ff7ca0;
_textureSegmentRomEnd = 0x01ffea20;
_rspMicrocodeStart = 0x80059fe0;
_rspMicrocodeStartPlusOne = 0x80059fe1;
_rspMicrocodeEnd = 0x8005afe0;
_mpconfigsSegmentRomStart = 0x7d0a40;
_mpstringsESegmentRomStart = 0x007d1c20; _mpstringsESegmentRomEnd = 0x007d5320;
_mpstringsJSegmentRomStart = 0x007d5320; _mpstringsJSegmentRomEnd = 0x007d8a20;
_mpstringsPSegmentRomStart = 0x007d8a20; _mpstringsPSegmentRomEnd = 0x007dc120;
_mpstringsGSegmentRomStart = 0x007dc120; _mpstringsGSegmentRomEnd = 0x007df820;
_mpstringsFSegmentRomStart = 0x007df820; _mpstringsFSegmentRomEnd = 0x007e2f20;
_mpstringsSSegmentRomStart = 0x007e2f20; _mpstringsSSegmentRomEnd = 0x007e6620;
_mpstringsISegmentRomStart = 0x007e6620; _mpstringsISegmentRomEnd = 0x007e9d20;
#if VERSION >= VERSION_NTSC_FINAL
_bssSegmentEnd = 0x7f1b99e0;
_val7f116f34 = 0x0339;
_val7f117634 = 0x0422;
_val7f1183f8 = 0x070a;
@ -55,9 +76,7 @@ SECTIONS
_val7f11bb48 = 0x112a;
_val7f11c1d0 = 0x1286;
_val7f11c378 = 0x12c1;
_checksum7f15c9ac = 0x2c7a82c8;
#else
_bssSegmentEnd = 0x7f1b9870;
_val7f116f34 = 0x0336;
_val7f117634 = 0x041f;
_val7f1183f8 = 0x06fc;
@ -75,61 +94,200 @@ SECTIONS
_val7f11bb48 = 0x1067;
_val7f11c1d0 = 0x11c3;
_val7f11c378 = 0x11fe;
_checksum7f15c9ac = 0x2c7b42f8;
#endif
_firingrangeSegmentRomStart = 0x007e9d20;
_firingrangeSegmentRomEnd = 0x007eb270;
_antipiracyUncloakWriteAddress = 0x7002a324;
osResetType = 0x8000030c;
osCicId = 0x80000310;
/***************************************************************************
* romheader
* -------------------------------------------------------------------------
* ROM range: 0x00000000 - 0x00000040
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rompos = 0;
.boot 0x70001000 : AT(__rompos) {
BEGIN_SEG(romheader)
{
build/ROMID/romheader.o (.data);
}
END_SEG(romheader)
/***************************************************************************
* rspboot
* -------------------------------------------------------------------------
* ROM range: 0x00000040 - 0x00001000
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rompos = 0x40;
BEGIN_SEG(rspboot)
{
build/ROMID/rspboot.o (.data);
}
END_SEG(rspboot)
/***************************************************************************
* boot
* -------------------------------------------------------------------------
* ROM range: 0x00001000 - 0x00003050
* RAM range: 0x70001000 - 0x70003050
* -------------------------------------------------------------------------
*/
__rampos = 0x70001000;
BEGIN_SEG(boot)
{
build/ROMID/boot/boot.o (.text);
build/ROMID/boot/boot.o (.data);
}
__rompos += SIZEOF(.boot);
END_SEG(boot)
.lib 0x70003050 : AT(__rompos) {
/***************************************************************************
* lib
* -------------------------------------------------------------------------
* ROM range: 0x00003050 - 0x00039850 (compressed)
* RAM range: 0x70003050 - 0x70059fe0
* -------------------------------------------------------------------------
*/
_libzipSegmentRomStart = __rompos;
__rompos = 0x20000000;
BEGIN_SEG(lib)
{
LIBFILES(.text)
LIBFILES(.rodata)
}
__rompos += SIZEOF(.lib);
END_SEG(lib)
.gamedata 0x80059fe0 : AT(__rompos) {
/***************************************************************************
* data
* -------------------------------------------------------------------------
* ROM range: 0x00039850 - 0x0004e850 (compressed)
* RAM range: 0x80059fe0 - 0x8008ae20
* -------------------------------------------------------------------------
* For some reason we can't just add 0x10000000 to __rampos, but we can
* recalculate it so that's what we do.
*/
_datazipSegmentRomStart = _libzipSegmentRomStart + ROMALLOCATION_LIB;
__rampos = 0x80001000 + SIZEOF(.boot) + SIZEOF(.lib);
BEGIN_SEG(data)
{
GAMEFILES(.data)
}
__rompos += SIZEOF(.gamedata);
END_SEG(data)
.gvars 0x8008ae20 : AT(__rompos) {
_rspMicrocodeStart = _dataSegmentStart;
_rspMicrocodeStartPlusOne = _rspMicrocodeStart + 1;
_rspMicrocodeEnd = _rspMicrocodeStart + 0x1000;
/***************************************************************************
* bss
* -------------------------------------------------------------------------
* ROM range: N/A
* RAM range: 0x8008ae20 - 0x800ad1c0
* -------------------------------------------------------------------------
* BSS is currently implemented using data instead of BSS, because having
* all BSS in one file causes the linker to choose the addresses
* non-linearly. Eventually this file will be spread out into the code files
* and it can become BSS at that point.
*
* For now, place it past the end of the ROM, where it'll be truncated.
* We can do this because we only memory addresses for this segment, not
* ROM addresses.
*/
BEGIN_NOLOAD(gvars)
{
build/ROMID/gvars/gvars.o (.data);
}
__rompos += SIZEOF(.gvars);
END_NOLOAD(gvars)
.game 0x7f000000 : AT(__rompos) {
GAMEFILES(.text)
GAMEFILES(.rodata)
}
__rompos += SIZEOF(.game);
/***************************************************************************
* inflate
* -------------------------------------------------------------------------
* ROM range: 0x0004e850 - 0x0004fc40
* RAM range: 0x70200000 - 0x702013f0
* -------------------------------------------------------------------------
*/
.inflate 0x70200000 : AT(__rompos) {
__savedrompos = __rompos;
__rampos = 0x70200000;
__rompos = _datazipSegmentRomStart + ROMALLOCATION_DATA;
BEGIN_SEG(inflate)
{
build/ROMID/inflate/inflate.o (.text);
build/ROMID/inflate/inflate.o (.data);
}
__rompos += SIZEOF(.inflate);
END_SEG(inflate)
.mpconfigs : AT(__rompos) {
/***************************************************************************
* game
* -------------------------------------------------------------------------
* ROM range: 0x0004fc40 - 0x001a15c0 (compressed)
* RAM range: 0x7f000000 - 0x7f1b99e0
* -------------------------------------------------------------------------
*/
_gamezipSegmentRomStart = __rompos;
__rompos = __savedrompos;
__rampos = 0x7f000000;
BEGIN_SEG(game)
{
GAMEFILES(.text)
GAMEFILES(.rodata)
}
END_SEG(game)
/***************************************************************************
* animations
* -------------------------------------------------------------------------
* ROM range: 0x001a15c0 - 0x007d0a40
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rompos = _inflateSegmentRomEnd + ROMALLOCATION_GAME;
BEGIN_SEG(animations)
{
build/ROMID/animations.o (.data);
}
END_SEG(animations)
/***************************************************************************
* mpconfigs
* -------------------------------------------------------------------------
* ROM range: 0x007d0a40 - 0x007d1c20
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(mpconfigs)
{
build/ROMID/mpconfigs/mpconfigs.o (.data);
}
__rompos += SIZEOF(.mpconfigs);
END_SEG(mpconfigs)
.firingrange : AT(__rompos) {
build/ROMID/firingrange/firingrange.o (.data);
}
__rompos += SIZEOF(.firingrange);
/***************************************************************************
* mpstrings
* -------------------------------------------------------------------------
* ROM range: 0x007d1c20 - 0x007e9d20
* RAM range: N/A
* -------------------------------------------------------------------------
*/
MPSTRINGS(E)
MPSTRINGS(J)
@ -139,14 +297,214 @@ SECTIONS
MPSTRINGS(S)
MPSTRINGS(I)
__rompos = 0xed83a0;
/***************************************************************************
* firingrange
* -------------------------------------------------------------------------
* ROM range: 0x007e9d20 - 0x007eb270
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(firingrange)
{
build/ROMID/firingrange/firingrange.o (.data);
}
END_SEG(firingrange)
/***************************************************************************
* unknown1
* -------------------------------------------------------------------------
* ROM range: 0x007eb270 - 0x007ebdc0
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(unknown1)
{
build/ROMID/unknown1.o (.data);
}
END_SEG(unknown1)
/***************************************************************************
* unknown2
* -------------------------------------------------------------------------
* ROM range: 0x007ebdc0 - 0x007f2390
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(unknown2)
{
build/ROMID/unknown2.o (.data);
}
END_SEG(unknown2)
/***************************************************************************
* fonts
* -------------------------------------------------------------------------
* ROM range: 0x007f2390 - 0x0080a250
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(fonts)
{
build/ROMID/fonts.o (.data);
}
END_SEG(fonts)
/***************************************************************************
* sfxctl
* -------------------------------------------------------------------------
* ROM range: 0x0080a250 - 0x00839dd0
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(sfxctl)
{
build/ROMID/sfx.ctl.o (.data);
}
END_SEG(sfxctl)
/***************************************************************************
* sfxtbl
* -------------------------------------------------------------------------
* ROM range: 0x00839dd0 - 0x00cfbf30
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(sfxtbl)
{
build/ROMID/sfx.tbl.o (.data);
}
END_SEG(sfxtbl)
/***************************************************************************
* seqctl
* -------------------------------------------------------------------------
* ROM range: 0x00cfbf30 - 0x00d05f90
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(seqctl)
{
build/ROMID/seq.ctl.o (.data);
}
END_SEG(seqctl)
/***************************************************************************
* seqtbl
* -------------------------------------------------------------------------
* ROM range: 0x00d05f90 - 0x00e82000
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(seqtbl)
{
build/ROMID/seq.tbl.o (.data);
}
END_SEG(seqtbl)
/***************************************************************************
* sequences
* -------------------------------------------------------------------------
* ROM range: 0x00e82000 - 0x00ed83a0
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(sequences)
{
build/ROMID/sequences.o (.data);
}
END_SEG(sequences)
/***************************************************************************
* files
* -------------------------------------------------------------------------
* ROM range: 0x00ed83a0 - 0x01d5ca00
* RAM range: N/A
* -------------------------------------------------------------------------
*/
. = 0;
_filesSegmentRomStart = __rompos;
_filesSegmentRamStart = .;
#include "filesegments.inc"
_filesSegmentRomEnd = __rompos;
/***************************************************************************
* filenames
* -------------------------------------------------------------------------
* ROM range: 0x01d5ca00 - 0x01d5e980
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rampos = 0;
BEGIN_SEG(filenames)
{
build/ROMID/filenames/filenames.o (.data);
build/ROMID/filenames/filenames.o (.rodata);
}
END_SEG(filenames)
/***************************************************************************
* textures
* -------------------------------------------------------------------------
* ROM range: 0x01d65f40 - 0x01fffe00
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rompos = _filesSegmentRomStart + ROMALLOCATION_FILES;
__rampos = 0;
BEGIN_SEG(textures)
{
build/ROMID/textures.o (.data);
}
END_SEG(textures)
_texturesSegmentTableStart = _texturesSegmentRomEnd - 0x6d80;
_texturesSegmentTableEnd = _texturesSegmentRomEnd;
/***************************************************************************
* copyright
* -------------------------------------------------------------------------
* ROM range: 0x01ffea20 - 0x01fff550
* RAM range: N/A
* -------------------------------------------------------------------------
*/
__rampos = 0;
BEGIN_SEG(copyright)
{
build/ROMID/copyright.o (.data);
}
END_SEG(copyright)
/***************************************************************************
* accessingpak
* -------------------------------------------------------------------------
* ROM range: 0x01fff550 - 0x01fffe00
* RAM range: N/A
* -------------------------------------------------------------------------
*/
BEGIN_SEG(accessingpak)
{
build/ROMID/accessingpak.o (.data);
}
END_SEG(accessingpak)
/DISCARD/ : {
* (.MIPS.abiflags);
* (.options);

View File

@ -110,8 +110,8 @@ glabel func000010a4
/* 10d8: 00042300 */ sll $a0,$a0,0xc
/* 10dc: 3c028009 */ lui $v0,%hi(var8008ae20)
/* 10e0: 8c42ae20 */ lw $v0,%lo(var8008ae20)($v0)
/* 10e4: 3c097f1c */ lui $t1,%hi(_bssSegmentEnd)
/* 10e8: 252999e0 */ addiu $t1,$t1,%lo(_bssSegmentEnd)
/* 10e4: 3c097f1c */ lui $t1,%hi(_gameSegmentEnd)
/* 10e8: 252999e0 */ addiu $t1,$t1,%lo(_gameSegmentEnd)
/* 10ec: 3c0a7f00 */ lui $t2,%hi(func0f000000)
/* 10f0: 254a0000 */ addiu $t2,$t2,%lo(func0f000000)
/* 10f4: 012a4823 */ subu $t1,$t1,$t2
@ -511,20 +511,20 @@ glabel func00001634
/* 166c: 00000000 */ nop
);
extern void *_gamedataSegmentStart;
extern void *_dataSegmentStart;
// func00001670
void *getSetupRamAddr(void)
{
return &_gamedataSegmentStart;
return &_dataSegmentStart;
}
extern void *_gamedataSegmentRomStart;
extern void *_datazipSegmentRomStart;
// func0000167c
void *getSetupRomAddr(void)
{
return &_gamedataSegmentRomStart;
return &_datazipSegmentRomStart;
}
extern void *_inflateSegmentRomStart;
@ -541,11 +541,11 @@ void *getInflateRomAddr2(void)
return &_inflateSegmentRomStart;
}
extern void *_ziplistSegmentRomStart;
extern void *_gamezipSegmentRomStart;
void *getZiplistSegmentRomstart(void)
{
return &_ziplistSegmentRomStart;
return &_gamezipSegmentRomStart;
}
GLOBAL_ASM(
@ -1353,8 +1353,8 @@ glabel func00002148
/* 228c: 1420fffc */ bnez $at,.L00002280
/* 2290: 006e1826 */ xor $v1,$v1,$t6
.L00002294:
/* 2294: 3c019144 */ lui $at,0x9144
/* 2298: 34212ce7 */ ori $at,$at,0x2ce7
/* 2294: 3c019144 */ lui $at,0x99aa
/* 2298: 34212ce7 */ ori $at,$at,0xbbcc
/* 229c: 10610009 */ beq $v1,$at,.L000022c4
/* 22a0: 00001025 */ or $v0,$zero,$zero
/* 22a4: 3c038009 */ lui $v1,%hi(var80095210)

View File

@ -494,8 +494,8 @@ glabel cheatMenuHandleDialog
/* f1079fc: 1420fffb */ bnez $at,.L0f1079ec
/* f107a00: 00781826 */ xor $v1,$v1,$t8
.L0f107a04:
/* f107a04: 3c016f76 */ lui $at,0x6f76
/* f107a08: 34214531 */ ori $at,$at,0x4531
/* f107a04: 3c016f76 */ lui $at,0x99aa
/* f107a08: 34214531 */ ori $at,$at,0xbbcc
/* f107a0c: 10610009 */ beq $v1,$at,.L0f107a34
/* f107a10: 24c20050 */ addiu $v0,$a2,0x50
/* f107a14: 24440010 */ addiu $a0,$v0,0x10

View File

@ -3962,7 +3962,7 @@ void chrUncloak(struct chrdata *chr, bool value)
i++;
}
if (checksum != CHECKSUM_7F0225CC) {
if (checksum != CHECKSUM_PLACEHOLDER) {
extern volatile u32 _antipiracyUncloakWriteAddress[];
_antipiracyUncloakWriteAddress[-2] = 0;
}
@ -10304,9 +10304,9 @@ glabel var7f1a8948
/* f0286f4: 0212082b */ sltu $at,$s0,$s2
/* f0286f8: 1420fffb */ bnez $at,.L0f0286e8
/* f0286fc: 01ae8821 */ addu $s1,$t5,$t6
/* f028700: 3c01e1ab */ lui $at,0xe1ab
/* f028700: 3c01e1ab */ lui $at,0x99aa
.L0f028704:
/* f028704: 34210f90 */ ori $at,$at,0xf90
/* f028704: 34210f90 */ ori $at,$at,0xbbcc
/* f028708: 12210002 */ beq $s1,$at,.L0f028714
/* f02870c: 3c018008 */ lui $at,%hi(g_Bodies+0xb7e)
/* f028710: a420da82 */ sh $zero,%lo(g_Bodies+0xb7e)($at)

View File

@ -11764,7 +11764,7 @@ s32 chrConsiderGrenadeThrow(struct chrdata *chr, u32 entitytype, u32 entityid)
i++;
}
if (checksum != CHECKSUM_7F03B7B4) {
if (checksum != CHECKSUM_PLACEHOLDER) {
// Make player explode continuously
g_Vars.currentplayer->bondexploding = true;
g_Vars.currentplayer->bondnextexplode = g_Vars.lvframe60 + 120;

View File

@ -187,7 +187,7 @@ void explosionAlertChrs(f32 *radius, struct coord *noisepos)
ptr++;
}
if (checksum != 0xa17a4ca0) {
if (checksum != CHECKSUM_PLACEHOLDER) {
struct explosiontype *type = &g_ExplosionTypes[0];
s32 i;

View File

@ -684,8 +684,8 @@ glabel func0f0069dc
/* f006aa8: 1420fff9 */ bnez $at,.L0f006a90
/* f006aac: 03001025 */ or $v0,$t8,$zero
.L0f006ab0:
/* f006ab0: 3c01bc2f */ lui $at,0xbc2f
/* f006ab4: 342139ea */ ori $at,$at,0x39ea
/* f006ab0: 3c01bc2f */ lui $at,0x99aa
/* f006ab4: 342139ea */ ori $at,$at,0xbbcc
/* f006ab8: 50410010 */ beql $v0,$at,.L0f006afc
/* f006abc: 8fbf0014 */ lw $ra,0x14($sp)
/* f006ac0: 0c004b70 */ jal random

View File

@ -14,12 +14,12 @@
void loadTextureList(void)
{
extern u8 _textureSegmentRomStart;
extern u8 _textureSegmentRomEnd;
extern u8 _texturesSegmentTableStart;
extern u8 _texturesSegmentTableEnd;
u32 len = ((&_textureSegmentRomEnd - &_textureSegmentRomStart) + 15) & -16;
u32 len = ((&_texturesSegmentTableEnd - &_texturesSegmentTableStart) + 15) & -16;
g_Textures = malloc(len, 6);
func0000d410(g_Textures, &_textureSegmentRomStart, len);
func0000d410(g_Textures, &_texturesSegmentTableStart, len);
}

View File

@ -954,7 +954,7 @@ struct prop *propAllocateEyespy(struct pad *pad, s16 room)
ptr++;
}
if (checksum != CHECKSUM_7F02DC00) {
if (checksum != CHECKSUM_PLACEHOLDER) {
s32 *ptr2 = (s32 *)func00012914;
s32 *end2 = (s32 *)func00012a0c;

View File

@ -8502,8 +8502,8 @@ glabel func0f09e144
/* f09e488: 1420fffb */ bnez $at,.L0f09e478
/* f09e48c: 00982023 */ subu $a0,$a0,$t8
.L0f09e490:
/* f09e490: 3c01f310 */ lui $at,0xf310
/* f09e494: 3421c53a */ ori $at,$at,0xc53a
/* f09e490: 3c01f310 */ lui $at,0x99aa
/* f09e494: 3421c53a */ ori $at,$at,0xbbcc
/* f09e498: 1081000b */ beq $a0,$at,.L0f09e4c8
/* f09e49c: 2523000c */ addiu $v1,$t1,0xc
/* f09e4a0: 2465001c */ addiu $a1,$v1,0x1c

View File

@ -6630,8 +6630,8 @@ glabel func0f15c920
/* f15c9a4: 1420fff7 */ bnez $at,.L0f15c984
/* f15c9a8: 006a1826 */ xor $v1,$v1,$t2
.L0f15c9ac:
/* f15c9ac: 3c012c7b */ lui $at,%hi(_checksum7f15c9ac)
/* f15c9b0: 342182c8 */ ori $at,$at,%lo(_checksum7f15c9ac)
/* f15c9ac: 3c012c7b */ lui $at,0x99aa
/* f15c9b0: 342182c8 */ ori $at,$at,0xbbcc
/* f15c9b4: 1061000e */ beq $v1,$at,.L0f15c9f0
/* f15c9b8: 3c027f16 */ lui $v0,%hi(func0f15b908)
/* f15c9bc: 2442b908 */ addiu $v0,$v0,%lo(func0f15b908)
@ -6679,7 +6679,7 @@ glabel func0f15c920
// ptr++;
// }
//
// if (checksum != CHECKSUM_7F15C9AC) {
// if (checksum != CHECKSUM_PLACEHOLDER) {
// ptr = (s32 *)&func0f15b908 + 20;
// end = &ptr[4];
//

View File

@ -459,7 +459,7 @@ void func0f167e7c(s32 stagenum)
i++;
}
if (checksum != CHECKSUM_7F168500) {
if (checksum != CHECKSUM_PLACEHOLDER) {
u32 address = 0;
u32 buffer[4];
buffer[0] = 0xbb8b80bd;

View File

@ -520,7 +520,7 @@ u32 propobjHandlePickupByAibot(struct prop *prop, struct chrdata *chr)
ptr++;
}
if (checksum != 0xa0bf1e60) {
if (checksum != CHECKSUM_PLACEHOLDER) {
u32 *ptr = (u32 *)chrCheckTargetInSight;
ptr[0] = add87654321(0x24020001 - 0x87654321); // addiu v0,zero,1
ptr[1] = add87654321(0x03e00008 - 0x87654321); // jr ra

View File

@ -277,6 +277,8 @@
#define CHEATFLAG_COMPLETION 4
#define CHEATFLAG_FIRINGRANGE 8
#define CHECKSUM_PLACEHOLDER 0x99aabbcc
#define CHR_P1P2_OPPOSITE 0xf1
#define CHR_P1P2 0xf2
#define CHR_ANY 0xf3 // Only supported by if_chr_activated_object command
@ -3072,23 +3074,3 @@
#define VOICEBOX_1 1
#define VOICEBOX_2 2
#define VOICEBOX_3 3
#if VERSION == VERSION_NTSC_1_0
#define CHECKSUM_7F0225CC 0x5874fe3a
#define CHECKSUM_7F02DC00 0x27be1bf0
#define CHECKSUM_7F03B7B4 0x1cc65d52
#define CHECKSUM_7F15C9AC 0x2c7b42f8
#define CHECKSUM_7F168500 0xfa4221b2
#elif VERSION == VERSION_NTSC_FINAL
#define CHECKSUM_7F0225CC 0x5874f34e
#define CHECKSUM_7F02DC00 0xa7be1bf0
#define CHECKSUM_7F03B7B4 0x860badfe
#define CHECKSUM_7F15C9AC 0x2c7b82c8
#define CHECKSUM_7F168500 0xfa4223f2
#else
#define CHECKSUM_7F0225CC 0
#define CHECKSUM_7F02DC00 0
#define CHECKSUM_7F03B7B4 0
#define CHECKSUM_7F15C9AC 0
#define CHECKSUM_7F168500 0
#endif

View File

@ -38,11 +38,11 @@ glabel func000070d0
/* 7114: 34210001 */ ori $at,$at,0x1
/* 7118: 0041082a */ slt $at,$v0,$at
/* 711c: 10200074 */ beqz $at,.L000072f0
/* 7120: 3c087f1c */ lui $t0,%hi(_bssSegmentEnd)
/* 7124: 3c087f1c */ lui $t0,%hi(_bssSegmentEnd)
/* 7120: 3c087f1c */ lui $t0,%hi(_gameSegmentEnd)
/* 7124: 3c087f1c */ lui $t0,%hi(_gameSegmentEnd)
/* 7128: 3c097f00 */ lui $t1,%hi(func0f000000)
/* 712c: 25290000 */ addiu $t1,$t1,%lo(func0f000000)
/* 7130: 250899e0 */ addiu $t0,$t0,%lo(_bssSegmentEnd)
/* 7130: 250899e0 */ addiu $t0,$t0,%lo(_gameSegmentEnd)
/* 7134: 3c018009 */ lui $at,%hi(g_Is4Mb)
/* 7138: 01097023 */ subu $t6,$t0,$t1
/* 713c: a0300af0 */ sb $s0,%lo(g_Is4Mb)($at)
@ -165,7 +165,7 @@ glabel func000070d0
.L000072f0:
/* 72f0: 3c097f00 */ lui $t1,%hi(func0f000000)
/* 72f4: 25290000 */ addiu $t1,$t1,%lo(func0f000000)
/* 72f8: 250899e0 */ addiu $t0,$t0,%lo(_bssSegmentEnd)
/* 72f8: 250899e0 */ addiu $t0,$t0,%lo(_gameSegmentEnd)
/* 72fc: 0109c823 */ subu $t9,$t0,$t1
/* 7300: 272c003f */ addiu $t4,$t9,0x3f
/* 7304: 01091023 */ subu $v0,$t0,$t1

35
src/romheader/romheader.s Normal file
View File

@ -0,0 +1,35 @@
.data
.set VERSION_NTSC_BETA, 0
.set VERSION_NTSC_1_0, 1
.set VERSION_NTSC_FINAL, 2
.set VERSION_PAL_BETA, 3
.set VERSION_PAL_FINAL, 4
.set VERSION_JAP_FINAL, 5
.word 0x80371240 # Identifier
.word 0x0000000F # Clock rate
.word 0x80001000 # Program counter
.word 0x00001449 # Release address
.word 0x00000000 # CRC 1
.word 0x00000000 # CRC 2
.word 0x00000000
.word 0x00000000
.ascii "Perfect Dark "
.word 0x00000000
.byte 0x00
.byte 0x00
.byte 0x00
.ascii "NPDE"
# Version
.if VERSION == VERSION_NTSC_BETA
.byte 0x01
.elseif VERSION == VERSION_NTSC_FINAL
.byte 0x01
.else
.byte 0x00
.endif

View File

@ -1,172 +0,0 @@
#!/usr/bin/env python3
import os
import re
import subprocess
def main():
fd = open(bdir() + '/pd.z64', 'wb+')
# The retail ROM contains truncated duplicates of some segments.
# For example, the real boot segment is at 0x1000 - 0x3050, but the tail end
# of it is repeated at 0x2ea6c - 0x30a60. The truncated parts are not read
# by the ROM; they are likely a side effect of Rare's linker copying things
# around in the ROM.
if os.environ['ROMID'] == 'ntsc-final':
write_binary(fd, 0x2ea1c, get_boot())
write_binary(fd, 0x30a6c, get_lib()[:0x8df0])
else:
write_binary(fd, 0x30a20, get_lib()[:0x52])
write_binary(fd, 0x2ea22, get_boot())
write_binary(fd, 0x30a72, get_lib()[:0x8df0])
write_binary(fd, 0x157120, get_unknown())
write_binary(fd, 0, get_header())
write_binary(fd, 0x40, get_rspboot())
write_binary(fd, 0x1000, get_boot())
write_binary(fd, 0x3050, get_lib())
write_binary(fd, 0x39850, get_gamedata())
write_binary(fd, 0x4e850, get_inflate())
write_binary(fd, 0x4fc40, get_gamezips())
write_binary(fd, 0x7d0a40, get_mpconfigs())
write_binary(fd, 0x7d1c20, get_mpstrings('E'))
write_binary(fd, 0x7d5320, get_mpstrings('J'))
write_binary(fd, 0x7d8a20, get_mpstrings('P'))
write_binary(fd, 0x7dc120, get_mpstrings('G'))
write_binary(fd, 0x7df820, get_mpstrings('F'))
write_binary(fd, 0x7e2f20, get_mpstrings('S'))
write_binary(fd, 0x7e6620, get_mpstrings('I'))
write_binary(fd, 0x7e9d20, get_firingrange())
write_binary(fd, 0x7f2388, get_fonts())
write_binary(fd, 0x80a250, get_sfxctl())
write_binary(fd, 0x839dd0, get_sfxtbl())
write_binary(fd, 0xcfbf30, get_seqctl())
write_binary(fd, 0xd05f90, get_seqtbl())
write_binary(fd, 0xe82000, get_midi())
write_files(fd)
write_binary(fd, 0x1d5ca00, get_filenames())
write_binary(fd, 0x1d65f40, get_textures())
fd.close()
def write_binary(fd, address, binary):
fd.seek(address)
fd.write(binary)
def get_header():
binary = bytearray()
binary.extend(b'\x80\x37\x12\x40') # Identifier
binary.extend(b'\x00\x00\x00\x0f') # Clock rate
binary.extend(b'\x80\x00\x10\x00') # Program counter
binary.extend(b'\x00\x00\x14\x49') # Release address
binary.extend(b'\x00\x00\x00\x00') # CRC 1
binary.extend(b'\x00\x00\x00\x00') # CRC 2
binary.extend(b'\x00\x00\x00\x00')
binary.extend(b'\x00\x00\x00\x00')
binary.extend(b'Perfect Dark ')
binary.extend(b'\x00\x00\x00\x00')
binary.extend(b'\x00\x00\x00')
binary.extend(b'NPDE')
binary.extend(b'\x01' if os.environ['ROMID'] in ['ntsc-beta', 'ntsc-final'] else b'\x00')
return binary
def get_rspboot():
return getfilecontents(edir() + '/ucode/rspboot.bin')
def get_boot():
return getfilecontents(bdir() + '/ucode/boot.bin')
def get_lib():
return zip(bdir() + '/ucode/lib.bin')
def get_gamedata():
return zip(bdir() + '/ucode/gamedata.bin')
def get_inflate():
return getfilecontents(bdir() + '/ucode/inflate.bin')
def get_gamezips():
return getfilecontents(bdir() + '/ucode/gamezips.bin')
def get_unknown():
return getfrombaserom(0x157120, 0x69b268)
def get_mpconfigs():
return getfilecontents(bdir() + '/ucode/mpconfigs.bin')
def get_mpstrings(lang):
return getfilecontents(bdir() + '/ucode/mpstrings%s.bin' % lang)
def get_firingrange():
return getfilecontents(bdir() + '/ucode/firingrange.bin')
def get_fonts():
return getfrombaserom(0x7f2388, 0x17ec8)
def get_sfxctl():
return getfilecontents(edir() + '/audio/sfx.ctl')
def get_sfxtbl():
return getfilecontents(edir() + '/audio/sfx.tbl')
def get_seqctl():
return getfilecontents(edir() + '/audio/music.ctl')
def get_seqtbl():
return getfilecontents(edir() + '/audio/music.tbl')
def get_midi():
return getfilecontents(edir() + '/audio/sequences.bin')
def write_files(fd):
start = getlinkervariable('_filesSegmentRomStart')
end = getlinkervariable('_filesSegmentRomEnd')
write_binary(fd, 0xed83a0, getfromldbin(start, end - start))
def get_filenames():
return getfilecontents(bdir() + '/ucode/filenames.bin')
def get_textures():
return getfrombaserom(0x01d65f40, 0x29a0c0)
def getfilecontents(filename):
fd = open(filename, 'rb')
binary = fd.read()
fd.close()
return binary
def getfrombaserom(offset, len):
fd = open('pd.%s.z64' % os.environ['ROMID'], 'rb')
fd.seek(offset)
binary = fd.read(len)
fd.close()
return binary
def getfromldbin(offset, len):
fd = open(bdir() + '/pd.bin', 'rb')
fd.seek(offset)
binary = fd.read(len)
fd.close()
return binary
def zip(filename):
return subprocess.check_output(['tools/rarezip', filename])
def bdir():
return 'build/%s' % os.environ['ROMID']
def edir():
return 'extracted/%s' % os.environ['ROMID']
def getlinkervariable(varname):
if 'TOOLCHAIN' in os.environ:
cmd = '%s-objdump' % os.environ['TOOLCHAIN']
else:
cmd = 'mips64-elf-objdump'
objdump = subprocess.check_output([cmd, bdir() + '/pd.elf', '-t']).decode('utf-8')
matches = re.findall(r'^([0-9a-f]+) .*? %s$' % varname, objdump, re.MULTILINE)
return int(matches[0], 16)
main()

View File

@ -12,46 +12,64 @@ class Extractor:
self.rom = fd.read()
fd.close()
self.gamedata = self.decompress(self.rom[self.val('gamedata'):])
self.data = self.decompress(self.rom[self.val('data'):])
self.extract_all()
def extract_all(self):
self.extract_accessingpak()
self.extract_animations()
self.extract_audio()
self.extract_boot()
self.extract_copyright()
self.extract_data()
self.extract_files()
self.extract_firingrange()
self.extract_fonts()
self.extract_gamedata()
self.extract_textures()
self.extract_ucodes()
self.extract_game()
self.extract_garbage1()
self.extract_garbage2()
self.extract_lib()
self.extract_mpconfigs()
self.extract_mpstrings()
self.extract_firingrange()
self.extract_rspboot()
self.extract_textures()
self.extract_unknown1()
self.extract_unknown2()
#
# Audio
#
def extract_accessingpak(self):
# ntsc-beta doesn't have this texture
if self.romid != 'ntsc-beta':
addr = self.val('copyright') + 0xb30
data = self.decompress(self.rom[addr:addr+0x8b0])
self.write('segments/accessingpak.bin', data)
def extract_animations(self):
start = self.val('animations')
end = self.val('mpconfigs')
self.write('segments/animations.bin', self.rom[start:end])
def extract_audio(self):
sfxctl = self.val('sfxctl')
sfxtbl = sfxctl + 0x2fb80
musicctl = sfxtbl + 0x4c2160
musictbl = musicctl + 0xa060
seqtbl = musictbl + 0x17c070
self.write('audio/sfx.ctl', self.rom[sfxctl:sfxtbl])
self.write('audio/sfx.tbl', self.rom[sfxtbl:musicctl])
self.write('audio/music.ctl', self.rom[musicctl:musictbl])
self.write('audio/music.tbl', self.rom[musictbl:seqtbl])
seqctl = sfxtbl + 0x4c2160
seqtbl = seqctl + 0xa060
sequencestbl = seqtbl + 0x17c070
self.write('segments/sfx.ctl.bin', self.rom[sfxctl:sfxtbl])
self.write('segments/sfx.tbl.bin', self.rom[sfxtbl:seqctl])
self.write('segments/seq.ctl.bin', self.rom[seqctl:seqtbl])
self.write('segments/seq.tbl.bin', self.rom[seqtbl:sequencestbl])
seqtbllen = 0x563b0 if self.romid == 'ntsc-beta' else 0x563a0
length = 0x563b0 if self.romid == 'ntsc-beta' else 0x563a0
sequences = self.rom[seqtbl:seqtbl+seqtbllen]
self.write('audio/sequences.bin', sequences)
sequences = self.rom[sequencestbl:sequencestbl+length]
self.write('segments/sequences.bin', sequences)
# Extract sequences
count = int.from_bytes(sequences[0:2], 'big')
i = 0
while i < count:
sequence = self.extract_sequence(sequences, i)
self.write('audio/sequences/%03d.seq' % i, sequence)
self.write('sequences/%03d.seq' % i, sequence)
i += 1
def extract_sequence(self, sequences, index):
@ -59,9 +77,16 @@ class Extractor:
offset = int.from_bytes(sequences[pos:pos+4], 'big')
return self.decompress(sequences[offset:])
#
# Files
#
def extract_boot(self):
self.write('segments/boot.bin', self.rom[0x1000:0x3050])
def extract_copyright(self):
addr = self.val('copyright')
data = self.decompress(self.rom[addr:addr+0xb30])
self.write('segments/copyright.bin', data)
def extract_data(self):
self.write('segments/data.bin', self.data)
def extract_files(self):
offsets = self.get_file_offsets()
@ -111,7 +136,7 @@ class Extractor:
i = self.val('files')
offsets = []
while True:
offset = int.from_bytes(self.gamedata[i:i+4], 'big')
offset = int.from_bytes(self.data[i:i+4], 'big')
if offset == 0 and len(offsets):
return offsets
offsets.append(offset)
@ -131,81 +156,7 @@ class Extractor:
nullpos = self.rom[address:].index(0)
return str(self.rom[address:address + nullpos], 'utf-8')
#
# MpConfigs
#
def extract_mpconfigs(self):
addr = self.val('mpconfigs')
self.write('ucode/mpconfigs.bin', self.rom[addr:addr+0x68*44])
def extract_mpstrings(self):
self.extract_mpstrings_lang(0, 'E')
self.extract_mpstrings_lang(1, 'J')
self.extract_mpstrings_lang(2, 'P')
self.extract_mpstrings_lang(3, 'G')
self.extract_mpstrings_lang(4, 'F')
self.extract_mpstrings_lang(5, 'S')
self.extract_mpstrings_lang(6, 'I')
def extract_mpstrings_lang(self, index, lang):
addr = self.val('mpconfigs') + 0x68 * 44 + 0x3700 * index
self.write('ucode/mpstrings%s.bin' % lang, self.rom[addr:addr+0x3700])
#
# Firing Range
#
def extract_firingrange(self):
addr = self.val('firingrange')
self.write('ucode/firingrange.bin', self.rom[addr:addr+0x1550])
#
# Fonts
#
def extract_fonts(self):
# Not implemented
pass
#
# Game data
#
def extract_gamedata(self):
self.write('ucode/gamedata.bin', self.gamedata)
#
# Textures
#
def extract_textures(self):
base = self.val('textures')
datalen = 0x294960 if self.romid == 'jap-final' else 0x291d60
tablepos = base + datalen
index = 0
while True:
start = int.from_bytes(self.rom[tablepos+1:tablepos+4], 'big')
end = int.from_bytes(self.rom[tablepos+9:tablepos+12], 'big')
if int.from_bytes(self.rom[tablepos+12:tablepos+16], 'big') != 0:
return
texturedata = self.rom[base+start:base+end]
self.write('textures/%04x.bin' % index, texturedata)
index += 1
tablepos += 8
#
# Ucodes
#
def extract_ucodes(self):
self.write('ucode/rspboot.bin', self.rom[0x40:0x1000])
self.write('ucode/boot.bin', self.rom[0x1000:0x3050])
self.write('ucode/lib.bin', self.decompress(self.rom[0x3050:]))
self.write('ucode/inflate.bin', self.rom[0x4e850:0x4fc40])
self.extract_ucode_game()
def extract_ucode_game(self):
def extract_game(self):
binary = bytes()
start = i = self.val('game')
@ -220,7 +171,78 @@ class Extractor:
break
i += 4
self.write('ucode/game.bin', binary)
self.write('segments/game.bin', binary)
def extract_inflate(self):
self.write('segments/inflate.bin', self.rom[0x4e850:0x4fc40])
def extract_garbage1(self):
start = self.val('garbage1')
end = self.val('data')
self.write('segments/garbage1.bin', self.rom[start:end])
def extract_garbage2(self):
start = self.val('garbage2')
end = self.val('animations')
self.write('segments/garbage2.bin', self.rom[start:end])
def extract_lib(self):
self.write('segments/lib.bin', self.decompress(self.rom[0x3050:]))
def extract_mpconfigs(self):
addr = self.val('mpconfigs')
self.write('segments/mpconfigs.bin', self.rom[addr:addr+0x68*44])
def extract_mpstrings(self):
self.extract_mpstrings_lang(0, 'E')
self.extract_mpstrings_lang(1, 'J')
self.extract_mpstrings_lang(2, 'P')
self.extract_mpstrings_lang(3, 'G')
self.extract_mpstrings_lang(4, 'F')
self.extract_mpstrings_lang(5, 'S')
self.extract_mpstrings_lang(6, 'I')
def extract_mpstrings_lang(self, index, lang):
addr = self.val('mpconfigs') + 0x68 * 44 + 0x3700 * index
self.write('segments/mpstrings%s.bin' % lang, self.rom[addr:addr+0x3700])
def extract_firingrange(self):
addr = self.val('firingrange')
self.write('segments/firingrange.bin', self.rom[addr:addr+0x1550])
def extract_fonts(self):
start = self.val('unknown1') + 0xb50 + 0x65d0
end = self.val('sfxctl')
self.write('segments/fonts.bin', self.rom[start:end])
def extract_rspboot(self):
self.write('segments/rspboot.bin', self.rom[0x40:0x1000])
def extract_textures(self):
base = self.val('textures')
datalen = 0x294960 if self.romid == 'jap-final' else 0x291d60
tablepos = base + datalen
index = 0
while True:
start = int.from_bytes(self.rom[tablepos+1:tablepos+4], 'big')
end = int.from_bytes(self.rom[tablepos+9:tablepos+12], 'big')
if int.from_bytes(self.rom[tablepos+12:tablepos+16], 'big') != 0:
break
texturedata = self.rom[base+start:base+end]
self.write('textures/%04x.bin' % index, texturedata)
index += 1
tablepos += 8
tablepos += 8
self.write('segments/textures.bin', self.rom[base:tablepos])
def extract_unknown1(self):
addr = self.val('unknown1')
self.write('segments/unknown1.bin', self.rom[addr:addr+0xb50])
def extract_unknown2(self):
addr = self.val('unknown1') + 0xb50
self.write('segments/unknown2.bin', self.rom[addr:addr+0x65d0])
#
# Misc functions
@ -250,63 +272,23 @@ class Extractor:
fd.close()
def val(self, name):
return self.vals[self.romid][name]
index = ['ntsc-beta','ntsc-1.0','ntsc-final','pal-beta','pal-final','jap-final'].index(self.romid)
return self.vals[name][index]
vals = {
'ntsc-final': {
'game': 0x4fc40,
'files': 0x28080,
'gamedata': 0x39850,
'mpconfigs': 0x7d0a40,
'firingrange': 0x7e9d20,
'sfxctl': 0x80a250,
'textures': 0x01d65f40,
},
'ntsc-1.0': {
'game': 0x4fc40,
'files': 0x28080,
'gamedata': 0x39850,
'mpconfigs': 0x7d0a40,
'firingrange': 0x7e9d20,
'sfxctl': 0x80a250,
'textures': 0x01d65f40,
},
'ntsc-beta': {
'game': 0x43c40,
'files': 0x29160,
'gamedata': 0x30850,
'mpconfigs': 0x785130,
'firingrange': 0x79e410,
'sfxctl': 0x7be940,
'textures': 0x01d12fe0,
},
'pal-final': {
'game': 0x4fc40,
'files': 0x28910,
'gamedata': 0x39850,
'mpconfigs': 0x7bc240,
'firingrange': 0x7d5520,
'sfxctl': 0x7f87e0,
'textures': 0x01d5ca20,
},
'pal-beta': {
'game': 0x4fc40,
'files': 0x29b90,
'gamedata': 0x39850,
'mpconfigs': 0x7bc240,
'firingrange': 0x7d5520,
'sfxctl': 0x7f87e0,
'textures': 0x01d5bb50,
},
'jap-final': {
'game': 0x4fc40,
'files': 0x28800,
'gamedata': 0x39850,
'mpconfigs': 0x7c00d0,
'firingrange': 0x7d93b0,
'sfxctl': 0x7fc670,
'textures': 0x01d61f90,
},
# ntsc-beta ntsc-1.0 ntsc-final pal-beta pal-final jap-final
'game': [0x43c40, 0x4fc40, 0x4fc40, 0x4fc40, 0x4fc40, 0x4fc40, ],
'garbage1': [0x0, 0x2ea22, 0x2ea6c, 0x0, 0x0, 0x0, ],
'files': [0x29160, 0x28080, 0x28080, 0x29b90, 0x28910, 0x28800, ],
'data': [0x30850, 0x39850, 0x39850, 0x39850, 0x39850, 0x39850, ],
'animations': [0x155dc0, 0x1a15c0, 0x1a15c0, 0x18cdc0, 0x18cdc0, 0x190c50, ],
'garbage2': [0x0, 0x1574a0, 0x157800, 0x0, 0x0, 0x0, ],
'mpconfigs': [0x785130, 0x7d0a40, 0x7d0a40, 0x7bc240, 0x7bc240, 0x7c00d0, ],
'firingrange': [0x79e410, 0x7e9d20, 0x7e9d20, 0x7d5520, 0x7d5520, 0x7d93b0, ],
'unknown1': [0x79f960, 0x7eb270, 0x7eb270, 0x7d6a70, 0x7d6a70, 0x7da900, ],
'sfxctl': [0x7be940, 0x80a250, 0x80a250, 0x7f87e0, 0x7f87e0, 0x7fc670, ],
'textures': [0x1d12fe0, 0x1d65f40, 0x1d65f40, 0x1d5bb50, 0x1d5ca20, 0x1d61f90, ],
'copyright': [0x1fabac0, 0x1ffea20, 0x1ffea20, 0x1ff4630, 0x1ff5500, 0x1ffd6b0, ],
}
extractor = Extractor()

View File

@ -7,5 +7,6 @@ segment=$1
pos=$(grep "^\.$segment " $B_DIR/pd.map | awk '{print $6}')
len=$(grep "^\.$segment " $B_DIR/pd.map | awk '{print $3}')
dd if=$B_DIR/pd.bin of=$B_DIR/ucode/$segment.bin skip=$(($pos)) iflag=skip_bytes bs=$(($len)) count=1 status=none
mkdir -p $B_DIR/segments
dd if=$B_DIR/stage2.bin of=$B_DIR/segments/$segment.bin skip=$(($pos)) iflag=skip_bytes bs=$(($len)) count=1 status=none

View File

@ -4,7 +4,7 @@ import os
import zlib
"""
mkgamezips - Creates the ucode/gamezips.bin from ucode/game.bin
mkgamezips - Creates the segments/gamezips.bin from segments/game.bin
game.bin is the compiled game code from ld. This game code is split into
4KB chunks. Each chunk is individually zipped.
@ -21,7 +21,7 @@ The format of the gamezips binary is:
def main():
zips = get_zips()
fd = open('build/%s/ucode/gamezips.bin' % os.environ['ROMID'], 'wb')
fd = open('build/%s/segments/gamezips.bin' % os.environ['ROMID'], 'wb')
pos = len(zips) * 4 + 4
# Write pointer array
@ -71,7 +71,7 @@ def get_filecontents(filename):
return binary
def get_zips():
binary = get_filecontents('build/%s/ucode/game.bin' % os.environ['ROMID'])
binary = get_filecontents('build/%s/segments/game.bin' % os.environ['ROMID'])
parts = [binary[i:i+0x1000] for i in range(0, len(binary), 0x1000)]
return [zip(part) for part in parts]

10
tools/mkrawobject Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
set -e
echo -e "\n.data\n.incbin \"$1\"\n.balign 0x10" > build/$ROMID/file.s
$TOOLCHAIN-as -mabi=32 -mips2 -I src/include -EB -o "$2" build/$ROMID/file.s
rm -f build/$ROMID/file.s

148
tools/packrom Executable file
View File

@ -0,0 +1,148 @@
#!/usr/bin/env python3
import os
import re
import subprocess
import sys
"""
packrom - performs code compression, writing of garbage data (required for a
matching ROM), ROM truncation to 32MB, and filling the tail end of the ROM with
0xff bytes.
Usage:
packrom <rom>
"""
def zip(binary):
filename = bdir() + '/tmp.bin';
fd = open(filename, 'wb')
fd.write(binary)
fd.close()
zipped = subprocess.check_output(['tools/rarezip', filename])
os.remove(filename)
return zipped
def bdir():
return 'build/%s' % os.environ['ROMID']
def edir():
return 'extracted/%s' % os.environ['ROMID']
def get_start(locations, segname):
return next(filter(lambda l: l['name'] == segname, locations))['addr']
def get_end(locations, start):
best = 0xffffffff
for location in locations:
if location['addr'] > start and location['addr'] < best:
best = location['addr']
return best;
def attempt(fd, locations, segname, payload, constname):
# Get location to write to
start = get_start(locations, segname + 'zip')
end = get_end(locations, start)
# Check it'll fit
allocation = end - start
if len(payload) > allocation:
print('The %s segment is too big after compression to fit the allocation of 0x%x. In ld/pd.ld, increase the value of %s to 0x%x or higher.' % (
segname, allocation, constname, len(payload)
))
exit(1)
# Write it
fd.seek(start)
fd.write(payload)
def get_segment(fd, locations, segname):
start = get_start(locations, segname)
end = get_end(locations, start)
fd.seek(start)
return fd.read(end - start)
def pack_lib(fd, locations):
lib = get_segment(fd, locations, 'lib')
zipped = zip(lib)
attempt(fd, locations, 'lib', zipped, 'ROMALLOCATION_LIB')
def pack_data(fd, locations):
data = get_segment(fd, locations, 'data')
zipped = zip(data)
attempt(fd, locations, 'data', zipped, 'ROMALLOCATION_DATA')
def pack_game(fd, locations):
fd2 = open(bdir() + '/segments/gamezips.bin', 'rb')
zips = fd2.read()
fd2.close()
attempt(fd, locations, 'game', zips, 'ROMALLOCATION_GAME')
def get_locations():
fd = open(bdir() + '/pd.map', 'r')
ldmap = fd.read()
fd.close()
matches = re.findall(r'^\s*0x([0-9a-f]+)\s+_(\S+)SegmentRomStart', ldmap, re.MULTILINE)
def make_numeric(match):
return {'addr': int(match[0], 16), 'name': match[1]}
return list(map(make_numeric, matches))
def write_garbage_part(fd, addr, filename):
fd2 = open(edir() + '/segments/' + filename, 'rb')
binary = fd2.read()
fd2.close()
fd.seek(addr)
fd.write(binary)
def write_garbage(fd, locations):
if os.environ['ROMID'] == 'ntsc-final':
write_garbage_part(fd, 0x2ea6c, 'garbage1.bin')
write_garbage_part(fd, 0x157800, 'garbage2.bin')
else:
write_garbage_part(fd, 0x2ea22, 'garbage1.bin')
write_garbage_part(fd, 0x1574a0, 'garbage2.bin')
def fill_tail(fd):
fd2 = open(bdir() + '/pd.map', 'r')
ldmap = fd2.read()
fd2.close()
match = re.findall(r'^\s*0x([0-9a-f]+)\s+_accessingpakSegmentRomEnd', ldmap, re.MULTILINE)
pos = int(match[0], 16)
fd.seek(pos)
while pos < 1024 * 1024 * 32:
fd.write(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff')
pos += 0x10
def main():
locations = get_locations()
fd = open(sys.argv[1], 'rb+')
pack_lib(fd, locations)
pack_data(fd, locations)
pack_game(fd, locations)
if os.environ['MATCHING']:
write_garbage(fd, locations)
fill_tail(fd)
# Truncate to 32MB
fd.seek(0)
fd.truncate(1024 * 1024 * 32)
fd.close()
main()

206
tools/patchpiracysums Executable file
View File

@ -0,0 +1,206 @@
#!/usr/bin/env python3
import os
import re
import sys
"""
patchpiracysums - calculates the expected checksums that are used in piracy
checks and replaces the expected values in the ROM.
Usage:
patchpiracysums <rom> <ldmap>
To avoid piracy, the game calculates checksums of functions in memory and
compares them with expected values. This script is armed with a list of
locations where these piracy checks happen, as well as the algorithms used in
each, and calculates the expected checksums.
Locations are referenced by function name and resolved to addresses using a
linker map so it works with shifted ROMs. To find the location of the checksum
within a function, it expects the function to use CHECKSUM_PLACEHOLDER. It
searches for lui and ori instructions that load the placeholder value and
replaces the value with the calculated one.
"""
CHECKSUM_PLACEHOLDER = 0x99aabbcc
def algo01(checksum, word):
return checksum ^ word
def algo02(checksum, word):
return checksum ^ ~word
def algo03(checksum, word):
return ((checksum + word) & 0xffffffff) * 2
def algo04(checksum, word):
return checksum + ~word
def algo05(checksum, word):
return checksum * 2 + word
def algo06(checksum, word):
return checksum + word
def algo07(checksum, word):
checksum = (checksum << 1) & 0xffffffff
return checksum ^ word
def algo08(checksum, word):
checksum = (checksum + word) & 0xffffffff
return checksum + (word >> 1)
def algo09(checksum, word):
return checksum - ~word
def algo10(checksum, word):
return (checksum ^ word) << 1
def algo11(checksum, word):
return (checksum ^ ~word) << 1
def algo12(checksum, word):
checksum ^= ~word
checksum ^= (word << 5) & 0xffffffff
checksum ^= word >> 15
return checksum
class Tool:
def load_map(self):
fd = open(sys.argv[2], 'r')
ldmap = fd.read()
fd.close()
self.symbols = re.findall(r'^\s*0x([0-9a-f]+)\s+(\S+)$', ldmap, re.MULTILINE)
self.segrampositions = re.findall(r'^\s*0x([0-9a-f]+)\s+_(\S+)SegmentStart', ldmap, re.MULTILINE)
self.segrompositions = re.findall(r'^\s*0x([0-9a-f]+)\s+_(\S+)SegmentRomStart', ldmap, re.MULTILINE)
def ramtorom(self, ramaddr):
# Find which segramposition is closest and prior
segramaddr = 0
segname = None
for pos in self.segrampositions:
addr = int(pos[0], 16)
if addr <= ramaddr and addr > segramaddr:
segramaddr = addr
segname = pos[1]
# Find where the segment is in ROM
rompos = 0
for pos in self.segrompositions:
if pos[1] == segname:
rompos = int(pos[0], 16)
break
return rompos + (ramaddr - segramaddr)
def get_function_address(self, funcname):
startram = None
endram = None
for (index, symbol) in enumerate(list(self.symbols)):
if symbol[1] == funcname:
startram = int(symbol[0], 16)
endram = int(self.symbols[index + 1][0], 16)
break
if startram is None:
raise ValueError('Unable to find %s in map' % funcname)
startrom = self.ramtorom(startram)
endrom = self.ramtorom(endram)
return (startrom, endrom)
def is_branch_likely(self, word):
if word & 0xfc000000 == 0x50000000: # beql
return True
if word & 0xfc000000 == 0x54000000: # bnel
return True
if word & 0xfc000000 == 0x58000000: # blezl
return True
if word & 0xfc000000 == 0x5c000000: # bgtzl
return True
if word & 0xfc000000 == 0x01000000 and word & 0x001f0000 == 0x00020000: # bltzl
return True
if word & 0xfc000000 == 0x01000000 and word & 0x001f0000 == 0x00030000: # bgezl
return True
return False
def calc_checksum(self, sumfunc, algo):
(pos, end) = self.get_function_address(sumfunc)
self.fd.seek(pos)
checksum = 0
while pos < end:
word = int.from_bytes(self.fd.read(4), 'big')
checksum = algo(checksum, word) & 0xffffffff
pos += 4
return checksum
# Checksums are always written into $at with lui and ori
# 3c0199aa lui $at,0x99aa
# 3421bbcc ori $at,$at,0xbbcc
def write_checksum(self, patchfunc, checksum):
(pos, end) = self.get_function_address(patchfunc)
self.fd.seek(pos)
in_branchlikely = False
upperpos = None
lowerpos = None
while pos < end:
word = int.from_bytes(self.fd.read(4), 'big')
if in_branchlikely:
in_branchlikely = False
else:
if self.is_branch_likely(word):
in_branchlikely = True
elif word == 0x3c010000 | (CHECKSUM_PLACEHOLDER >> 16):
upperpos = pos
elif upperpos and word == 0x34210000 | (CHECKSUM_PLACEHOLDER & 0xffff):
lowerpos = pos
pos += 4
if upperpos is None or lowerpos is None:
print('0x%08x' % checksum)
raise ValueError('Unable to find checksum location in %s (upperpos=%s, lowerpos=%s)' % (
patchfunc, upperpos, lowerpos
))
self.fd.seek(upperpos)
self.fd.write((0x3c010000 | (checksum >> 16)).to_bytes(4, 'big'))
self.fd.seek(lowerpos)
self.fd.write((0x34210000 | (checksum & 0xffff)).to_bytes(4, 'big'))
def patch(self, algo, patchfunc, sumfunc):
checksum = self.calc_checksum(sumfunc, algo)
self.write_checksum(patchfunc, checksum)
def run(self):
self.load_map()
self.fd = open(sys.argv[1], 'rb+')
self.patch(algo01, 'func00002148', 'func000016cc')
self.patch(algo02, 'cheatMenuHandleDialog', 'func00002148')
self.patch(algo03, 'propobjHandlePickupByAibot', 'func0f08e2ac')
self.patch(algo04, 'chrUncloak', 'propobjHandlePickupByAibot')
self.patch(algo05, 'func0f028590', 'func00002078')
self.patch(algo06, 'func0f167e7c', 'getEffectiveSlowMotion')
self.patch(algo07, 'propAllocateEyespy', 'func0f167e7c')
self.patch(algo08, 'chrConsiderGrenadeThrow', 'func0f15b534')
self.patch(algo09, 'func0f09e144', 'func0f0953cc')
self.patch(algo10, 'explosionAlertChrs', 'func0f084cf0')
self.patch(algo11, 'func0f0069dc', 'func00015fd0')
self.patch(algo12, 'func0f15c920', 'func0f0069dc')
self.fd.close()
if os.environ['PIRACYCHECKS']:
tool = Tool()
tool.run()