Upgrade to splat 0.9.0 (#730)

* changes for splat 0.9.0

* wip

* git subrepo pull --branch=develop --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "2ff7357501"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "develop"
  commit:   "2ff7357501"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* OK

* big_snowflakes gfx data

* Jenkins?

* cleanup

* debuff effect gfx data

* fix

* more effect gfx data

* dlabel

* git subrepo pull --branch=experiment --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "1365775e09"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "experiment"
  commit:   "1365775e09"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* .

* git subrepo pull --branch=experiment --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "6bd9fe1c4e"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "experiment"
  commit:   "6bd9fe1c4e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* flower splash/trail gfx

* throw_spiny gfx

* disable_x and butterflies gfx data

* draw_coin_sparkles

* Warnings, cleanup

* cleanin

* attempt at test_item_player_collision

* more gfx + cleanup

* more effect gfx

* func_8002D160

* update update_symbol_addrs and symbol_addrs

* git subrepo pull --branch=develop --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "4914dc9029"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "develop"
  commit:   "4914dc9029"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull --branch=master --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "aa71299594"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "aa71299594"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* fix

* fix regression

* Add rabbitizer to requirements

* warnings

* symbol_addrs fixes
This commit is contained in:
Ethan Roseman 2022-06-12 11:33:32 -04:00 committed by GitHub
parent 763b320bfb
commit bae34c46ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 5107 additions and 2651 deletions

1
Jenkinsfile vendored
View File

@ -13,6 +13,7 @@ pipeline {
sh 'curl -L "https://github.com/ethteck/ido-static-recomp/releases/download/per-function/ido-5.3-recomp-ubuntu-latest.tar.gz" | tar zx -C tools/build/cc/ido5.3'
sh 'curl -L "https://github.com/decompals/mips-gcc-2.7.2/releases/download/main/gcc-2.7.2-linux.tar.gz" | tar zx -C tools/build/cc/gcc2.7.2'
sh 'curl -L "https://github.com/decompals/mips-binutils-2.6/releases/download/main/binutils-2.6-linux.tar.gz" | tar zx -C tools/build/cc/gcc2.7.2'
sh 'pip install -r requirements.txt'
sh './configure'
}
}

View File

@ -2439,4 +2439,20 @@ typedef struct FoldImageRecPart {
/* 0x11 */ char unk_11[0x7];
} FoldImageRecPart; // size = 0x18
typedef struct FoldImageRec {
/* 0x00 */ s8* raster;
/* 0x04 */ s8* palette;
/* 0x08 */ u16 width;
/* 0x0A */ u16 height;
/* 0x0C */ s16 xOffset;
/* 0x0E */ s16 yOffset;
/* 0x10 */ u8 unk_10;
/* 0x11 */ char unk_11[0x7];
/* 0x18 */ s16 unk_18;
/* 0x1A */ char unk_1A[0x4];
/* 0x1E */ s16 unk_1E;
/* 0x20 */ char unk_20[0x4];
/* 0x24 */ u8 alphaMultiplier;
} FoldImageRec; // size = 0x25
#endif

View File

@ -434,6 +434,11 @@ typedef struct AttackResultTextFXData {
/* 0x34 */ f32 unk_34;
} AttackResultTextFXData; // size = 0x38
typedef struct GotItemOutlineFXData {
/* 0x00 */ char unk_00[0x14];
/* 0x14 */ s32 unk_14;
} GotItemOutlineFXData; // size = ???
typedef struct SmallGoldSparkleFXData {
/* 0x00 */ s32 unk_00;
/* 0x04 */ s32 unk_04;

View File

@ -786,6 +786,7 @@ void entity_base_block_init(Entity* entity);
s32 entity_start_script(Entity* entity);
void remove_item_entity_by_index(s32 index);
void set_entity_commandlist(Entity* entity, s32* entityScript);
s32 func_800DFCF4(void);
void func_800EF3E4(void);
void func_80268858(void);
void func_80269118(void);

View File

@ -7,3 +7,7 @@ ninja_syntax
msgpack
pylibyaml
tqdm
spimdisasm
pygfxd
intervaltree
rabbitizer

View File

@ -1,15 +1,15 @@
#include "common.h"
extern void(*D_8004AA85)(void);
extern void(*obfuscated_create_audio_system)(void);
void func_80200000(void) {
u32 t0 = 0xAC29007B;
u32 t1 = 0xB00006A8;
void(*create_audio_subsystem)(void) = &D_8004AA85;
void(*create_audio_system)(void) = &obfuscated_create_audio_system;
while (IO_READ(PI_STATUS_REG) & 3);
t0 -= IO_READ(t1 - 0x1C8);
create_audio_subsystem += t0;
create_audio_subsystem();
create_audio_system += t0;
create_audio_system();
}

View File

@ -3,12 +3,12 @@
#include "ld_addrs.h"
#include "mips.h"
extern s32 D_7012BC11[];
extern s32 obfuscated_general_heap_create[];
void func_802AE000_316C00(void) {
s32(*readFunc)(OSPiHandle*, u32, u32*) = osEPiReadIo;
s32 seed = 0x3C016C07 + 0xFEFEFEF;
HeapNode*(*generalHeapCreate)(void) = D_7012BC11; // general_heap_create - 0xFEFEFEF
HeapNode*(*generalHeapCreate)(void) = obfuscated_general_heap_create; // general_heap_create - 0xFEFEFEF
u32 hash = 0;
u32 thisInsn;
u32* it;

View File

@ -2,12 +2,12 @@
#include "ld_addrs.h"
#include "mips.h"
extern s32 D_80026AC7[];
extern s32 obfuscated_load_engine_data[];
void func_80200080(void) {
s32 seed = 0x3C01A775;
u32 thisInsn = 0xB0018FFC;
HeapNode*(*load_engine_data)(s32) = D_80026AC7; // load_engine_data - ????????
HeapNode*(*load_engine_data)(s32) = obfuscated_load_engine_data; // load_engine_data - ????????
s32 hash = 0;
u32 prevInsn;
u32* it;

View File

@ -3,12 +3,12 @@
#include "ld_addrs.h"
#include "mips.h"
extern s32 D_7012ACA1[];
extern s32 obfuscated_battle_heap_create[];
void func_802AE000(void) {
s32(*readFunc)(OSPiHandle*, u32, u32*) = osEPiReadIo;
s32 seed = 0x33F50000;
UNK_FUN_PTR(battle_heap_create) = D_7012ACA1;
UNK_FUN_PTR(battle_heap_create) = obfuscated_battle_heap_create;
u32 hash = 0;
u32 thisInsn;
u32* it;

View File

@ -1,3 +1,75 @@
#include "common.h"
#include "nu/nusys.h"
#include "ld_addrs.h"
#include "mips.h"
INCLUDE_ASM(s32, "8560", func_8002D160);
extern s8 D_F79DDD0F[];
extern s8 D_7599F6D8[];
void func_8002D160(void) {
s32 (*readFunc)(OSPiHandle*, u32, u32*);
s32 (*readFunc2)(OSPiHandle*, u32, u32*);
s8* vramDest = D_7599F6D8;
s8* romStart = D_F79DDD0F;
s32 seed;
u32 hash;
u32 thisInsn;
u32 thisInsn2;
u32 prevInsn;
u8* it;
// vramDest
readFunc = osEPiReadIo;
seed = 0x0B112D28;
hash = 0;
readFunc(nuPiCartHandle, 0xB0000D10, &thisInsn);
seed -= thisInsn;
prevInsn = 0;
for (it = _316D90_ROM_START; it < _316D90_ROM_END; it += 4) {
readFunc(nuPiCartHandle, (u32)it, &thisInsn);
hash += LOWER(thisInsn) + UPPER(thisInsn);
if (OPCODE(prevInsn) == LUI && (OPCODE(thisInsn) == ADDIU || OPCODE(thisInsn) == LW)) {
if (GET_RS(thisInsn) == GET_RT(prevInsn) && GET_RS(thisInsn) == GET_RT(thisInsn)) {
hash -= LOWER(thisInsn);
hash -= LOWER(prevInsn);
}
}
if (OPCODE(thisInsn) == JAL) {
hash -= LOWER(thisInsn) + (UPPER(thisInsn) & 0xFC00);
}
prevInsn = thisInsn;
}
vramDest += seed + 0x2A4EB6 - hash;
// romStart
readFunc2 = osEPiReadIo;
seed = 0x18F414AB;
hash = 0;
readFunc2(nuPiCartHandle, 0xB0000E38, &thisInsn2);
seed -= thisInsn2;
prevInsn = 0;
for (it = _316F30_ROM_START; it < _316F30_ROM_END; it += 4) {
readFunc2(nuPiCartHandle, (u32)it, &thisInsn2);
hash += LOWER(thisInsn2) + UPPER(thisInsn2);
if (OPCODE(prevInsn) == LUI && (OPCODE(thisInsn2) == ADDIU || OPCODE(thisInsn2) == LW)) {
if (GET_RS(thisInsn2) == GET_RT(prevInsn) && GET_RS(thisInsn2) == GET_RT(thisInsn2)) {
hash -= LOWER(thisInsn2);
hash -= LOWER(prevInsn);
}
}
if (OPCODE(thisInsn2) == JAL) {
hash -= LOWER(thisInsn2) + (UPPER(thisInsn2) & 0xFC00);
}
prevInsn = thisInsn2;
}
romStart += seed + 0xED41C - hash;
dma_copy(romStart, _316F30_ROM_END, vramDest);
}

View File

@ -1,27 +1,37 @@
#include "common.h"
#include "effects.h"
#include "hud_element.h"
#include "pause/pause_common.h"
#include "world/partners.h"
#include "sparkle_script.h"
#define MAX_ITEM_ENTITIES 256
extern SparkleScript SparkleScript_Coin;
extern Lights1 D_8014C6C8;
extern s32 ItemEntitiesCreated;
extern s32 D_80155D80;
extern s32 ItemEntityAlternatingSpawn;
extern s32 ItemEntityRenderGroup;
extern s16 D_80155D8C;
extern s16 D_80155D8E;
extern s16 D_80155D90;
extern ItemEntity* WorldItemEntities[MAX_ITEM_ENTITIES];
extern ItemEntity* BattleItemEntities[MAX_ITEM_ENTITIES];
extern ItemEntity** gCurrentItemEntities;
extern s16 isPickingUpItem;
extern s32 D_80155D80;
extern s16 D_80155D8C;
extern s16 D_80155D8E;
extern s16 D_80155D90;
extern s16 D_801565A6;
extern s16 D_801565A8;
extern PopupMenu D_801565B0;
extern s32 D_801568E0;
extern s32 D_801568E4;
extern s32 D_801568E8;
extern s32 D_801568EC;
extern SparkleScript SparkleScript_Coin;
extern EffectInstance* D_801568F0;
extern MessagePrintState* D_801568F4;
extern s32 D_801568F8;
void item_entity_load(ItemEntity*);
void item_entity_update(ItemEntity*);
@ -239,7 +249,6 @@ void draw_coin_sparkles(ItemEntity* itemEntity) {
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
gDPPipeSync(gMasterGfxPos++);
}
ItemEntity* get_item_entity(s32 itemEntityIndex) {
@ -884,7 +893,151 @@ void func_80133A94(s32 idx, s32 itemID) {
item_entity_load(item);
}
// float/stack crap
#ifdef NON_EQUIVALENT
s32 test_item_player_collision(ItemEntity* item) {
PlayerStatus* playerStatus = &gPlayerStatus;
PartnerActionStatus* partnerActionStatus = &gPartnerActionStatus;
EncounterStatus* encounterStatus = &gCurrentEncounter;
Camera* camera = &gCameras[gCurrentCameraID];
s32 actionState;
f32 t;
f32 itemX;
f32 itemY;
f32 itemZ;
f32 playerX;
f32 playerY;
f32 playerZ;
f32 sp10;
f32 sp14;
f32 sp1C;
f32 sp20;
f32 sp24;
f32 zDiff;
f32 temp_f14;
f32 xDiff;
f32 angle;
s32 cond;
f32 f1;
actionState = playerStatus->actionState;
if (item->flags & 0x100) {
item->flags &= ~0x100;
return TRUE;
}
if (gGameState != 2 && gGameState != 0) {
return FALSE;
}
if (encounterStatus->hitType == 5) {
return FALSE;
}
if (item->flags & 0x200000) {
return FALSE;
}
if (isPickingUpItem) {
return FALSE;
}
if (item->flags & 0x40) {
return FALSE;
}
if (get_time_freeze_mode() != 0) {
return FALSE;
}
if (partnerActionStatus->partnerActionState != 0 && partnerActionStatus->actingPartner == 9) {
return FALSE;
}
if ((actionState == 0x1D || actionState == 0x1E || actionState == 0x1F) && item->itemID != ITEM_COIN) {
return FALSE;
}
if (gOverrideFlags & 0x200000) {
return FALSE;
}
cond = FALSE;
sp1C = playerStatus->colliderHeight / 2;
playerX = playerStatus->position.x;
playerY = playerStatus->position.y;
playerZ = playerStatus->position.z;
sp20 = playerStatus->colliderDiameter / 4;
if (playerStatus->spriteFacingAngle < 180.0f) {
temp_f14 = clamp_angle(camera->currentYaw - 90.0f);
} else {
temp_f14 = clamp_angle(camera->currentYaw + 90.0f);
}
sp10 = playerX;
sp24 = playerY;
sp14 = playerZ;
if (get_clamped_angle_diff(camera->currentYaw, temp_f14) < 0.0f) {
angle = clamp_angle(camera->currentYaw - 90.0f);
if (playerStatus->trueAnimation & 0x01000000) {
angle = clamp_angle(angle + 30.0f);
}
} else {
angle = clamp_angle(camera->currentYaw + 90.0f);
if (playerStatus->trueAnimation & 0x01000000) {
angle = clamp_angle(angle - 30.0f);
}
}
add_vec2D_polar(&sp10, &sp14, 24.0f, angle);
itemX = item->position.x;
itemY = item->position.y;
itemZ = item->position.z;
t = 13.5f;
xDiff = itemX - playerX;
zDiff = itemZ - playerZ;
f1 = sqrtf(SQ(xDiff) + SQ(zDiff));
if (!(sp20 + t <= f1) &&
!(itemY + 27.0f < playerY) &&
!(playerY + sp1C < itemY))
{
cond = TRUE;
}
if (playerStatus->actionState == 0x12 && (playerStatus->flags & 0x01000000)) {
xDiff = itemX - sp10;
zDiff = itemZ - sp14;
f1 = sqrtf(SQ(xDiff) + SQ(zDiff));
if (!(14.0f + t <= f1) &&
!(itemY + 27.0f < sp24) &&
!(sp24 + 18.0f < itemY))
{
cond = TRUE;
}
}
if (cond) {
if (item->flags & 0x80) {
if (D_801565A6 != 0) {
D_801565A6--;
return FALSE;
} else {
item->flags &= ~0x80;
}
}
return TRUE;
}
if (item->flags & 0x80) {
item->flags &= ~0x80;
}
return FALSE;
}
#else
INCLUDE_ASM(s32, "C50A0", test_item_player_collision);
#endif
s32 test_item_entity_position(f32 x, f32 y, f32 z, f32 dist) {
ItemEntity* item;

View File

@ -10,7 +10,7 @@
#include "common/GetSelectedMoveID.inc.c"
ApiStatus SetActorLevelToZero(Evt* script, s32 isInitialCall) {
ApiStatus N(SetActorLevelToZero)(Evt* script, s32 isInitialCall) {
get_actor(script->owner1.actorID)->actorBlueprint->level = 0;
return ApiStatus_DONE2;
}
@ -798,7 +798,7 @@ EvtScript N(fallOff) = {
EVT_CALL(ResetAllActorSounds, ACTOR_SELF)
EVT_CALL(GetActorSize, ACTOR_SELF, LW(0), LW(1))
EVT_CALL(SetActorSize, ACTOR_SELF, 24, LW(1))
EVT_CALL(SetActorLevelToZero)
EVT_CALL(N(SetActorLevelToZero))
EVT_RETURN
EVT_END
};

View File

@ -36,22 +36,6 @@ typedef struct FoldDataCache {
/* 0x06 */ char unk_06[0x2];
} FoldDataCache; // size = 0x8
typedef struct FoldImageRec {
/* 0x00 */ s8* raster;
/* 0x04 */ s8* palette;
/* 0x08 */ u16 width;
/* 0x0A */ u16 height;
/* 0x0C */ s16 xOffset;
/* 0x0E */ s16 yOffset;
/* 0x10 */ u8 unk_10;
/* 0x11 */ char unk_11[0x7];
/* 0x18 */ s16 unk_18;
/* 0x1A */ char unk_1A[0x4];
/* 0x1E */ s16 unk_1E;
/* 0x20 */ char unk_20[0x4];
/* 0x24 */ u8 alphaMultiplier;
} FoldImageRec; // size = 0x25
typedef struct FoldGfxDescriptor {
/* 0x00 */ Vtx* vtx;
/* 0x04 */ Gfx* gfx;

View File

@ -28,20 +28,20 @@ extern s32 D_801A6000;
EffectTableEntry gEffectTable[] = {
/* 0x00 */ {},
/* 0x01 */ FX_ENTRY(big_smoke_puff, _326410),
/* 0x01 */ FX_ENTRY(big_smoke_puff, effect_gfx_big_smoke_puff),
/* 0x02 */ {},
/* 0x03 */ {},
/* 0x04 */ {},
/* 0x05 */ {},
/* 0x06 */ FX_ENTRY(landing_dust, _328EA0),
/* 0x07 */ FX_ENTRY(walking_dust, _328EA0),
/* 0x08 */ FX_ENTRY(flower_splash, _32CEC0),
/* 0x09 */ FX_ENTRY(flower_trail, _32CEC0),
/* 0x0A */ FX_ENTRY(cloud_puff, _32EC50),
/* 0x0B */ FX_ENTRY(cloud_trail, _32EC50),
/* 0x0C */ FX_ENTRY(footprint, _32FB50),
/* 0x0D */ FX_ENTRY(floating_flower, _330460),
/* 0x0E */ FX_ENTRY(snowflake, _330F00),
/* 0x08 */ FX_ENTRY(flower_splash, effect_gfx_flower_splash_trail),
/* 0x09 */ FX_ENTRY(flower_trail, effect_gfx_flower_splash_trail),
/* 0x0A */ FX_ENTRY(cloud_puff, effect_gfx_cloud_puff_trail),
/* 0x0B */ FX_ENTRY(cloud_trail, effect_gfx_cloud_puff_trail),
/* 0x0C */ FX_ENTRY(footprint, effect_gfx_footprint),
/* 0x0D */ FX_ENTRY(floating_flower, effect_gfx_floating_flower),
/* 0x0E */ FX_ENTRY(snowflake, effect_gfx_snowflake),
/* 0x0F */ FX_ENTRY(star, _3326A0),
/* 0x10 */ FX_ENTRY(emote, _334C70),
/* 0x11 */ FX_ENTRY(sparkles, _337FC0),
@ -57,7 +57,7 @@ EffectTableEntry gEffectTable[] = {
/* 0x1B */ FX_ENTRY(got_item_outline, _345B40),
/* 0x1C */ FX_ENTRY(spiky_white_aura, _34E770),
/* 0x1D */ FX_ENTRY(smoke_impact, _328EA0),
/* 0x1E */ FX_ENTRY(damage_indicator, _350220),
/* 0x1E */ FX_ENTRY(damage_indicator, effect_gfx_damage_indicator),
/* 0x1F */ FX_ENTRY(purple_ring, _352CE0),
/* 0x20 */ FX_ENTRY(flame, _353BB0),
/* 0x21 */ FX_ENTRY(stars_burst, _343040),
@ -75,8 +75,8 @@ EffectTableEntry gEffectTable[] = {
/* 0x2D */ FX_ENTRY(stars_spread, _360A30),
/* 0x2E */ FX_ENTRY(steam_burst, _361670),
/* 0x2F */ FX_ENTRY(stars_orbiting, _362C50),
/* 0x30 */ FX_ENTRY(big_snowflakes, _3638C0),
/* 0x31 */ FX_ENTRY(debuff, _364C00),
/* 0x30 */ FX_ENTRY(big_snowflakes, effect_gfx_big_snowflakes),
/* 0x31 */ FX_ENTRY(debuff, effect_gfx_debuff),
/* 0x32 */ FX_ENTRY(green_impact, _3659B0),
/* 0x33 */ FX_ENTRY(radial_shimmer, _366D60),
/* 0x34 */ FX_ENTRY(ending_decals, _36AEE0),
@ -92,7 +92,7 @@ EffectTableEntry gEffectTable[] = {
/* 0x3E */ FX_ENTRY(blast, _37D9D0),
/* 0x3F */ FX_ENTRY(fire_flower, _3803A0),
/* 0x40 */ FX_ENTRY(recover, _381E00),
/* 0x41 */ FX_ENTRY(disable_x, _3863B0),
/* 0x41 */ FX_ENTRY(disable_x, effect_gfx_disable_x),
/* 0x42 */ FX_ENTRY(bombette_breaking, _37D9D0),
/* 0x43 */ FX_ENTRY(firework, _38A350),
/* 0x44 */ FX_ENTRY(confetti, _38BBA0),
@ -100,7 +100,7 @@ EffectTableEntry gEffectTable[] = {
/* 0x46 */ FX_ENTRY_NUMBERED(46, _38E990),
/* 0x47 */ FX_ENTRY(gather_magic, _38F710),
/* 0x48 */ FX_ENTRY(attack_result_text, _3903D0),
/* 0x49 */ FX_ENTRY(small_gold_sparkle, _392440),
/* 0x49 */ FX_ENTRY(small_gold_sparkle, effect_gfx_small_gold_sparkle),
/* 0x4A */ FX_ENTRY(flashing_box_shockwave, _3930A0),
/* 0x4B */ FX_ENTRY(balloon, _394670),
/* 0x4C */ FX_ENTRY(floating_rock, _3960F0),
@ -112,7 +112,7 @@ EffectTableEntry gEffectTable[] = {
/* 0x52 */ FX_ENTRY(energy_orb_wave, _3A4320),
/* 0x53 */ FX_ENTRY(merlin_house_stars, _3A5BE0),
/* 0x54 */ FX_ENTRY(quizmo_audience, _3A77A0),
/* 0x55 */ FX_ENTRY(butterflies, _3AB030),
/* 0x55 */ FX_ENTRY(butterflies, effect_gfx_butterflies),
/* 0x56 */ FX_ENTRY(stat_change, _3AF700),
/* 0x57 */ FX_ENTRY(snaking_static, _3B2D90),
/* 0x58 */ FX_ENTRY(thunderbolt_ring, _3B46A0),
@ -127,7 +127,7 @@ EffectTableEntry gEffectTable[] = {
/* 0x61 */ FX_ENTRY(fright_jar, _3C1BA0),
/* 0x62 */ FX_ENTRY(stop_watch, _3CB890),
/* 0x63 */ FX_ENTRY_NUMBERED(63, _3CD6E0),
/* 0x64 */ FX_ENTRY(throw_spiny, _3CFAF0),
/* 0x64 */ FX_ENTRY(throw_spiny, effect_gfx_throw_spiny),
/* 0x65 */ FX_ENTRY_NUMBERED(65, _3D11E0),
/* 0x66 */ FX_ENTRY(tubba_heart_attack, _3D2580),
/* 0x67 */ FX_ENTRY(whirlwind, _3D3930),

View File

@ -6,16 +6,17 @@ static f32 D_E0002788[10] = { 2.2f, 2.7f, 3.0f, 2.2f, 2.7f, 3.0f, 1.9f, 1.9f, 1.
static f32 sPartScales[10] = { 1.4f, 1.3f, 1.2f, 1.3f, 1.4f, 1.3f, 1.6f, 1.6f, 1.6f, 1.6f };
static f32 sPartYaws[10] = { 0.0f, 234.0f, 468.0f, 702.0f, 936.0f, 1260.0f, 1404.0f, 1638.0f, 1902.0f, 1976.0f };
extern Gfx D_09000FA0[];
extern Gfx D_09001060[];
extern Gfx D_09001120[];
extern Gfx D_090011E0[];
extern Gfx D_090012A0[];
extern Gfx D_09001360[];
extern Gfx D_09001420[];
extern Gfx D_09000FA0_3273B0[];
extern Gfx D_09001060_327470[];
extern Gfx D_09001120_327530[];
extern Gfx D_090011E0_3275F0[];
extern Gfx D_090012A0_3276B0[];
extern Gfx D_09001360_327770[];
extern Gfx D_09001420_327830[];
static Gfx* sDlists[7] = {
D_09000FA0, D_09001060, D_09001120, D_090011E0, D_090012A0, D_09001360, D_09001420
D_09000FA0_3273B0, D_09001060_327470, D_09001120_327530, D_090011E0_3275F0, D_090012A0_3276B0, D_09001360_327770,
D_09001420_327830
};
void big_smoke_puff_init(EffectInstance* effect);

View File

@ -1,12 +1,12 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09000900[];
extern Gfx D_090009E8[];
extern Gfx D_09000A10[];
extern Gfx D_09000900_3641C0[];
extern Gfx D_090009E8_3642A8[];
extern Gfx D_09000A10_3642D0[];
Gfx* D_E0060730[] = { D_090009E8, D_09000A10 };
Gfx* D_E0060738[] = { D_09000900, D_09000900 };
Gfx* D_E0060730[] = { D_090009E8_3642A8, D_09000A10_3642D0 };
Gfx* D_E0060738[] = { D_09000900_3641C0, D_09000900_3641C0 };
void big_snowflakes_init(EffectInstance* effect);
void big_snowflakes_update(EffectInstance* effect);

View File

@ -1,27 +1,28 @@
#include "common.h"
#include "effects_internal.h"
extern Vtx D_09002D40[][6]; // TODO confirm this type is correct
extern Gfx D_09003880[];
extern Gfx D_090038F8[];
extern Gfx D_09003968[];
extern Gfx D_090039D8[];
extern Gfx D_09003A48[];
extern Gfx D_09003AB8[];
extern Gfx D_09003B28[];
extern Gfx D_09003B98[];
extern Gfx D_09003C08[];
extern Gfx D_09003C78[];
extern Gfx D_09003CE8[];
extern Gfx D_09003D58[];
extern Gfx D_09003DC8[];
extern Vtx D_09002D40_3ADD70[][6]; // TODO confirm this type is correct
extern Gfx D_09003880_3AE8B0[];
extern Gfx D_090038F8_3AE928[];
extern Gfx D_09003968_3AE998[];
extern Gfx D_090039D8_3AEA08[];
extern Gfx D_09003A48_3AEA78[];
extern Gfx D_09003AB8_3AEAE8[];
extern Gfx D_09003B28_3AEB58[];
extern Gfx D_09003B98_3AEBC8[];
extern Gfx D_09003C08_3AEC38[];
extern Gfx D_09003C78_3AECA8[];
extern Gfx D_09003CE8_3AED18[];
extern Gfx D_09003D58_3AED88[];
extern Gfx D_09003DC8_3AEDF8[];
Gfx* D_E00AA6C0[11] = {
D_090038F8, D_09003968, D_090039D8, D_09003A48, D_09003AB8, D_09003B28, D_09003B98, D_09003C08, D_09003C78, D_09003CE8, D_09003D58
D_090038F8_3AE928, D_09003968_3AE998, D_090039D8_3AEA08, D_09003A48_3AEA78, D_09003AB8_3AEAE8, D_09003B28_3AEB58, D_09003B98_3AEBC8, D_09003C08_3AEC38, D_09003C78_3AECA8, D_09003CE8_3AED18, D_09003D58_3AED88
};
s8 D_E00AA6EC[] = {
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0, 0 };
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0, 0
};
void butterflies_init(EffectInstance* effect);
void butterflies_update(EffectInstance* effect);
@ -181,10 +182,10 @@ void butterflies_appendGfx(void* effect) {
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetPrimColor(gMasterGfxPos++, 0, 0, primColor, primColor, primColor, 255);
gSPDisplayList(gMasterGfxPos++, D_09003880);
gSPDisplayList(gMasterGfxPos++, D_09003880_3AE8B0);
gSPDisplayList(gMasterGfxPos++, D_E00AA6C0[type]);
gSPVertex(gMasterGfxPos++, &D_09002D40[data->unk_2C], 6, 0);
gSPDisplayList(gMasterGfxPos++, D_09003DC8);
gSPVertex(gMasterGfxPos++, &D_09002D40_3ADD70[data->unk_2C], 6, 0);
gSPDisplayList(gMasterGfxPos++, D_09003DC8_3AEDF8);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
gDPPipeSync(gMasterGfxPos++);
}

View File

@ -1,8 +1,8 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_090000E0[];
extern Gfx D_090001B8[];
extern Gfx D_090000E0_32ED30[];
extern Gfx D_090001B8_32EE08[];
void cloud_puff_init(EffectInstance* effect);
void cloud_puff_update(EffectInstance* effect);
@ -121,7 +121,7 @@ void cloud_puff_appendGfx(void* effect) {
gDPPipeSync(gMasterGfxPos++);
gSPSegment(gMasterGfxPos++, 0x09, VIRTUAL_TO_PHYSICAL(effectTemp->graphics->data));
gSPDisplayList(gMasterGfxPos++, D_090000E0);
gSPDisplayList(gMasterGfxPos++, D_090000E0_32ED30);
for (i = 0; i < effectTemp->numParts; i++, part++) {
if (part->alive) {
@ -134,7 +134,7 @@ void cloud_puff_appendGfx(void* effect) {
gDPSetPrimColor(gMasterGfxPos++, 0, 0, 112, 96, 24, part->alpha);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++],
G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_090001B8);
gSPDisplayList(gMasterGfxPos++, D_090001B8_32EE08);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
}

View File

@ -1,8 +1,8 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_090000E0[];
extern Gfx D_090001B8[];
extern Gfx D_090000E0_32ED30[];
extern Gfx D_090001B8_32EE08[];
void cloud_trail_init(EffectInstance* effect);
void cloud_trail_update(EffectInstance* effect);
@ -122,7 +122,7 @@ void cloud_trail_appendGfx(void* effect) {
gDPPipeSync(gMasterGfxPos++);
gSPSegment(gMasterGfxPos++, 0x09, VIRTUAL_TO_PHYSICAL(effectTemp->graphics->data));
gSPDisplayList(gMasterGfxPos++, D_090000E0);
gSPDisplayList(gMasterGfxPos++, D_090000E0_32ED30);
for (i = 0; i < effectTemp->numParts; i++, part++) {
if (part->alive) {
@ -137,7 +137,7 @@ void cloud_trail_appendGfx(void* effect) {
gDPSetPrimColor(gMasterGfxPos++, 0, 0, 112, 96, 24, part->alpha);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++],
G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_090001B8);
gSPDisplayList(gMasterGfxPos++, D_090001B8_32EE08);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
}

View File

@ -1,34 +1,34 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09001D40[];
extern Gfx D_09001DE0[];
extern Gfx D_09001E50[];
extern Gfx D_09001E90[];
extern Gfx D_09001ED0[];
extern Gfx D_09001F10[];
extern Gfx D_09001F50[];
extern Gfx D_09001F90[];
extern Gfx D_09001FD0[];
extern Gfx D_09002010[];
extern Gfx D_09002050[];
extern Gfx D_09002090[];
extern Gfx D_090020D0[];
extern Gfx D_09002110[];
extern Gfx D_09002150[];
extern Gfx D_09002160[];
extern Gfx D_09002170[];
extern Gfx D_09002180[];
extern Gfx D_090021A8[];
extern Gfx D_09002190[];
extern Gfx D_090021C0[];
extern Gfx D_090021E0[];
extern Gfx D_09002200[];
extern Gfx D_09001D40_351F60[];
extern Gfx D_09001DE0_352000[];
extern Gfx D_09001E50_352070[];
extern Gfx D_09001E90_3520B0[];
extern Gfx D_09001ED0_3520F0[];
extern Gfx D_09001F10_352130[];
extern Gfx D_09001F50_352170[];
extern Gfx D_09001F90_3521B0[];
extern Gfx D_09001FD0_3521F0[];
extern Gfx D_09002010_352230[];
extern Gfx D_09002050_352270[];
extern Gfx D_09002090_3522B0[];
extern Gfx D_090020D0_3522F0[];
extern Gfx D_09002110_352330[];
extern Gfx D_09002150_352370[];
extern Gfx D_09002160_352380[];
extern Gfx D_09002170_352390[];
extern Gfx D_09002180_3523A0[];
extern Gfx D_09002190_3523B0[];
extern Gfx D_090021A8_3523C8[];
extern Gfx D_090021C0_3523E0[];
extern Gfx D_090021E0_352400[];
extern Gfx D_09002200_352420[];
Gfx* D_E003CCA0[] = {
D_09001E50, D_09001E90, D_09001ED0, D_09001F10,
D_09001F50, D_09001F90, D_09001FD0, D_09002010,
D_09002050, D_09002090, D_090020D0, D_09002110
D_09001E50_352070, D_09001E90_3520B0, D_09001ED0_3520F0, D_09001F10_352130,
D_09001F50_352170, D_09001F90_3521B0, D_09001FD0_3521F0, D_09002010_352230,
D_09002050_352270, D_09002090_3522B0, D_090020D0_3522F0, D_09002110_352330
};
u8 D_E003CCD0[] = {
@ -224,20 +224,20 @@ void func_E003C498(EffectInstance* effect) {
for (i = 1; i < effect->numParts; i++, part--) {
s32 index = (i + spA0);
gDPSetPrimColor(gMasterGfxPos++, 0, 0, D_E003CCF8[index % 12].r, D_E003CCF8[index % 12].g, D_E003CCF8[index % 12].b, part->alpha);
gSPDisplayList(gMasterGfxPos++, D_09001D40);
gSPDisplayList(gMasterGfxPos++, D_09001D40_351F60);
if (i == spA4) {
shim_guPositionF(sp20, 0.0f, 0.0f, 0.0f, part->unk_38, part->unk_10.x, part->unk_10.y, part->unk_10.z);
shim_guMtxF2L(sp20, &gDisplayContext->matrixStack[gMatrixListPos]);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_09002150);
gSPDisplayList(gMasterGfxPos++, D_09002150_352370);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
shim_guPositionF(sp20, 0.0f, 0.0f, 0.0f, part->unk_38, (part->unk_10.x + part->unk_04.x) * 0.5, (part->unk_10.y + part->unk_04.y) * 0.5, (part->unk_10.z + part->unk_04.z) * 0.5);
shim_guMtxF2L(sp20, &gDisplayContext->matrixStack[gMatrixListPos]);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_09002160);
gSPDisplayList(gMasterGfxPos++, D_09002160_352380);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
gSPDisplayList(gMasterGfxPos++, D_09001D40);
gSPDisplayList(gMasterGfxPos++, D_09001D40_351F60);
shim_guTranslateF(sp20, part->unk_04.x, part->unk_04.y, part->unk_04.z);
shim_guMtxF2L(sp20, &gDisplayContext->matrixStack[gMatrixListPos]);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
@ -246,27 +246,27 @@ void func_E003C498(EffectInstance* effect) {
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
if (i == spA4) {
gSPDisplayList(gMasterGfxPos++, &D_09002170);
gSPDisplayList(gMasterGfxPos++, &D_09002170_352390);
} else {
gSPDisplayList(gMasterGfxPos++, &D_09002180);
gSPDisplayList(gMasterGfxPos++, &D_09002180_3523A0);
}
if (i == spA4) {
gSPDisplayList(gMasterGfxPos++, D_090021A8);
gSPDisplayList(gMasterGfxPos++, D_090021A8_3523C8);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_09001DE0);
gSPDisplayList(gMasterGfxPos++, D_090021E0_352400);
if (spA8 < 10) {
gSPDisplayList(gMasterGfxPos++, D_E003CCA0[i]);
gSPDisplayList(gMasterGfxPos++, D_090021C0);
gSPDisplayList(gMasterGfxPos++, D_090021C0_3523E0);
} else {
s32 temp = spA8 % 10;
s32 temp2 = spA8 / 10;
gSPDisplayList(gMasterGfxPos++, D_E003CCA0[temp]);
gSPDisplayList(gMasterGfxPos++, D_09002200);
gSPDisplayList(gMasterGfxPos++, D_09002200_352420);
gSPDisplayList(gMasterGfxPos++, D_E003CCA0[temp2]);
gSPDisplayList(gMasterGfxPos++, D_090021E0);
gSPDisplayList(gMasterGfxPos++, D_090021E0_352400);
}
} else {
gSPDisplayList(gMasterGfxPos++, D_09002190);
gSPDisplayList(gMasterGfxPos++, D_09002190_3523B0);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);

View File

@ -1,11 +1,11 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09000240[];
extern Gfx D_090002E8[];
extern Gfx D_09000240_364E40[];
extern Gfx D_090002E8_364EE8[];
Gfx* D_E00628C0[] = { D_090002E8 };
Gfx* D_E00628C4[] = { D_09000240 };
Gfx* D_E00628C0[] = { D_090002E8_364EE8 };
Gfx* D_E00628C4[] = { D_09000240_364E40 };
void debuff_init(EffectInstance* effect);
void debuff_update(EffectInstance* effect);

View File

@ -1,29 +1,29 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09002100[];
extern Gfx D_09002198[];
extern Gfx D_09002230[];
extern Gfx D_09002250[];
extern Gfx D_09002270[];
extern Gfx D_09002290[];
extern Gfx D_090022B0[];
extern Gfx D_09002320[];
extern Gfx D_09002360[];
extern Gfx D_090023A0[];
extern Gfx D_090023E0[];
extern Gfx D_09002420[];
extern Gfx D_09002460[];
extern Gfx D_090024A0[];
extern Gfx D_090024E0[];
extern Gfx D_09002520[];
extern Gfx D_09002560[];
extern Gfx D_090025A0[];
extern Gfx D_090025E0[];
extern Gfx D_09002100_3884B0[];
extern Gfx D_09002198_388548[];
extern Gfx D_09002230_3885E0[];
extern Gfx D_09002250_388600[];
extern Gfx D_09002270_388620[];
extern Gfx D_09002290_388640[];
extern Gfx D_090022B0_388660[];
extern Gfx D_09002320_3886D0[];
extern Gfx D_09002360_388710[];
extern Gfx D_090023A0_388750[];
extern Gfx D_090023E0_388790[];
extern Gfx D_09002420_3887D0[];
extern Gfx D_09002460_388810[];
extern Gfx D_090024A0_388850[];
extern Gfx D_090024E0_388890[];
extern Gfx D_09002520_3888D0[];
extern Gfx D_09002560_388910[];
extern Gfx D_090025A0_388950[];
extern Gfx D_090025E0_388990[];
Gfx* D_E0082D00[] = {
D_09002320, D_09002360, D_090023A0, D_090023E0, D_09002420, D_09002460, D_090024A0, D_090024E0, D_09002520,
D_09002560, D_090025A0, D_090025E0
D_09002320_3886D0, D_09002360_388710, D_090023A0_388750, D_090023E0_388790, D_09002420_3887D0, D_09002460_388810,
D_090024A0_388850, D_090024E0_388890, D_09002520_3888D0, D_09002560_388910, D_090025A0_388950, D_090025E0_388990
};
void disable_x_init(EffectInstance* effect);
@ -269,12 +269,12 @@ void func_E00828B4(EffectInstance* effect) {
for (i = 1; i < effect->numParts; i++, data++) {
if (unk_38 > 0 || type == 10) {
if (type == 1) {
gSPDisplayList(gMasterGfxPos++, D_09002198);
gSPDisplayList(gMasterGfxPos++, D_09002198_388548);
} else {
gSPDisplayList(gMasterGfxPos++, D_09002100);
gSPDisplayList(gMasterGfxPos++, D_09002100_3884B0);
}
func_E00826C4(data);
gSPDisplayList(gMasterGfxPos++, D_09002230);
gSPDisplayList(gMasterGfxPos++, D_09002230_3885E0);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
}
@ -296,19 +296,19 @@ void func_E0082A84(EffectInstance* effect) {
for (i = 1; i < effect->numParts; i++, data++) {
func_E00826C4(data);
if (unk_38 > 0) {
gSPDisplayList(gMasterGfxPos++, D_090022B0);
gSPDisplayList(gMasterGfxPos++, D_090022B0_388660);
if (unk_38 < 10) {
gSPDisplayList(gMasterGfxPos++, D_E0082D00[unk_38]);
gSPDisplayList(gMasterGfxPos++, D_09002250);
gSPDisplayList(gMasterGfxPos++, D_09002250_388600);
} else {
s32 ones = unk_38 % 10;
s32 tens = unk_38 / 10;
gSPDisplayList(gMasterGfxPos++, D_E0082D00[ones]);
gSPDisplayList(gMasterGfxPos++, D_E0082D00[tens]);
gSPDisplayList(gMasterGfxPos++, D_09002290);
gSPDisplayList(gMasterGfxPos++, D_09002290_388640);
gSPDisplayList(gMasterGfxPos++, D_E0082D00[tens]);
gSPDisplayList(gMasterGfxPos++, D_09002270);
gSPDisplayList(gMasterGfxPos++, D_09002270_388620);
}
}
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);

View File

@ -3,7 +3,7 @@
s32 D_E001A610 = 0;
extern Gfx D_090002F0[];
extern Gfx D_090002F0_330750[];
void floating_flower_init(EffectInstance* effect);
void floating_flower_update(EffectInstance* effect);
@ -164,7 +164,7 @@ void floating_flower_appendGfx(void* effect) {
if (alpha != 0) {
gDPSetPrimColor(gMasterGfxPos++, 0, 0, 0, 0, 0, alpha);
gSPDisplayList(gMasterGfxPos++, D_090002F0);
gSPDisplayList(gMasterGfxPos++, D_090002F0_330750);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
}

View File

@ -1,7 +1,7 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09000E08[];
extern Gfx D_09000E08_32DCC8[];
void flower_splash_init(EffectInstance* effect);
void flower_splash_update(EffectInstance* effect);
@ -147,7 +147,7 @@ void flower_splash_appendGfx(void* effect) {
for (i = 0; i < effectTemp->numParts; i++, data++) {
if (data->unk_00 != 0) {
Gfx* dlist = D_09000E08;
Gfx* dlist = D_09000E08_32DCC8;
gDisplayContext->matrixStack[gMatrixListPos] = data->unk_30;

View File

@ -1,8 +1,8 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09000E20[];
extern Gfx D_09000E38[];
extern Gfx D_09000E20_32DCE0[];
extern Gfx D_09000E38_32DCF8[];
void flower_trail_init(EffectInstance* effect);
void flower_trail_update(EffectInstance* effect);
@ -167,9 +167,9 @@ void flower_trail_appendGfx(void* effect) {
for (i = 0; i < effectTemp->numParts; i++, part++) {
if (part->unk_00 != 0) {
if (part->unk_09 != 0) {
dlist = D_09000E20;
dlist = D_09000E20_32DCE0;
} else {
dlist = D_09000E38;
dlist = D_09000E38_32DCF8;
}
gDisplayContext->matrixStack[gMatrixListPos] = part->unk_30;

View File

@ -1,7 +1,7 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_09000240[];
extern Gfx D_09000240_32FD90[];
void func_E0018000(FootprintFXData* part);
void footprint_init(EffectInstance* effect);
@ -124,7 +124,7 @@ void footprint_appendGfx(void* effect) {
for (i = 0; i < effectTemp->numParts; i++, part++) {
if (part->alive) {
Gfx* dlist = D_09000240;
Gfx* dlist = D_09000240_32FD90;
gDisplayContext->matrixStack[gMatrixListPos] = part->mtx;

View File

@ -0,0 +1,28 @@
#include "common.h"
#include "effects/gfx/D_09000000_326410.png.inc.c"
#include "effects/gfx/D_09000000_326410.pal.inc.c"
#include "effects/gfx/D_09000220_326630.png.inc.c"
#include "effects/gfx/D_09000220_326630.pal.inc.c"
#include "effects/gfx/D_09000440_326850.png.inc.c"
#include "effects/gfx/D_09000440_326850.pal.inc.c"
#include "effects/gfx/D_09000660_326A70.png.inc.c"
#include "effects/gfx/D_09000660_326A70.pal.inc.c"
#include "effects/gfx/D_09000880_326C90.png.inc.c"
#include "effects/gfx/D_09000880_326C90.pal.inc.c"
#include "effects/gfx/D_09000AA0_326EB0.png.inc.c"
#include "effects/gfx/D_09000AA0_326EB0.pal.inc.c"
#include "effects/gfx/D_09000CC0_3270D0.png.inc.c"
#include "effects/gfx/D_09000CC0_3270D0.pal.inc.c"
#include "effects/gfx/D_09000EE0_3272F0.vtx.inc.c"
#include "effects/gfx/D_09000F20_327330.gfx.inc.c"
#include "effects/gfx/D_09000F88_327398.gfx.inc.c"
#include "effects/gfx/D_09000FA0_3273B0.gfx.inc.c"
#include "effects/gfx/D_09001060_327470.gfx.inc.c"
#include "effects/gfx/D_09001120_327530.gfx.inc.c"
#include "effects/gfx/D_090011E0_3275F0.gfx.inc.c"
#include "effects/gfx/D_090012A0_3276B0.gfx.inc.c"
#include "effects/gfx/D_09001360_327770.gfx.inc.c"
#include "effects/gfx/D_09001420_327830.gfx.inc.c"

View File

@ -0,0 +1,11 @@
#include "common.h"
#include "effects/gfx/D_09000000_3638C0.png.inc.c"
#include "effects/gfx/D_09000080_363940.png.inc.c"
#include "effects/gfx/D_09000880_364140.vtx.inc.c"
#include "effects/gfx/D_090008C0_364180.vtx.inc.c"
#include "effects/gfx/D_09000900_3641C0.gfx.inc.c"
#include "effects/gfx/D_090009E8_3642A8.gfx.inc.c"
#include "effects/gfx/D_09000A10_3642D0.gfx.inc.c"

View File

@ -0,0 +1,40 @@
#include "common.h"
#include "effects/gfx/D_09000000_3AB030.png.inc.c"
#include "effects/gfx/D_09000000_3AB030.pal.inc.c"
#include "effects/gfx/D_09000420_3AB450.png.inc.c"
#include "effects/gfx/D_09000420_3AB450.pal.inc.c"
#include "effects/gfx/D_09000840_3AB870.png.inc.c"
#include "effects/gfx/D_09000840_3AB870.pal.inc.c"
#include "effects/gfx/D_09000C50_3ABC80.png.inc.c"
#include "effects/gfx/D_09000C50_3ABC80.pal.inc.c"
#include "effects/gfx/D_09001070_3AC0A0.png.inc.c"
#include "effects/gfx/D_09001070_3AC0A0.pal.inc.c"
#include "effects/gfx/D_09001480_3AC4B0.png.inc.c"
#include "effects/gfx/D_09001480_3AC4B0.pal.inc.c"
#include "effects/gfx/D_090018A0_3AC8D0.png.inc.c"
#include "effects/gfx/D_090018A0_3AC8D0.pal.inc.c"
#include "effects/gfx/D_09001CC0_3ACCF0.png.inc.c"
#include "effects/gfx/D_09001CC0_3ACCF0.pal.inc.c"
#include "effects/gfx/D_090020E0_3AD110.png.inc.c"
#include "effects/gfx/D_090020E0_3AD110.pal.inc.c"
#include "effects/gfx/D_09002500_3AD530.png.inc.c"
#include "effects/gfx/D_09002500_3AD530.pal.inc.c"
#include "effects/gfx/D_09002920_3AD950.png.inc.c"
#include "effects/gfx/D_09002920_3AD950.pal.inc.c"
#include "effects/gfx/D_09002D40_3ADD70.vtx.inc.c"
#include "effects/gfx/D_09003880_3AE8B0.gfx.inc.c"
#include "effects/gfx/D_090038F8_3AE928.gfx.inc.c"
#include "effects/gfx/D_09003968_3AE998.gfx.inc.c"
#include "effects/gfx/D_090039D8_3AEA08.gfx.inc.c"
#include "effects/gfx/D_09003A48_3AEA78.gfx.inc.c"
#include "effects/gfx/D_09003AB8_3AEAE8.gfx.inc.c"
#include "effects/gfx/D_09003B28_3AEB58.gfx.inc.c"
#include "effects/gfx/D_09003B98_3AEBC8.gfx.inc.c"
#include "effects/gfx/D_09003C08_3AEC38.gfx.inc.c"
#include "effects/gfx/D_09003C78_3AECA8.gfx.inc.c"
#include "effects/gfx/D_09003CE8_3AED18.gfx.inc.c"
#include "effects/gfx/D_09003D58_3AED88.gfx.inc.c"
#include "effects/gfx/D_09003DC8_3AEDF8.gfx.inc.c"

View File

@ -0,0 +1,9 @@
#include "common.h"
#include "effects/gfx/D_09000000_32EC50.png.inc.c"
#include "effects/gfx/D_09000000_32EC50.pal.inc.c"
#include "effects/gfx/D_090000A0_32ECF0.vtx.inc.c"
#include "effects/gfx/D_090000E0_32ED30.gfx.inc.c"
#include "effects/gfx/D_090001B8_32EE08.gfx.inc.c"

View File

@ -0,0 +1,48 @@
#include "common.h"
#include "effects/gfx/D_09000000_350220.png.inc.c"
#include "effects/gfx/D_09000200_350420.png.inc.c"
#include "effects/gfx/D_09000400_350620.png.inc.c"
#include "effects/gfx/D_09000600_350820.png.inc.c"
#include "effects/gfx/D_09000800_350A20.png.inc.c"
#include "effects/gfx/D_09000A00_350C20.png.inc.c"
#include "effects/gfx/D_09000C00_350E20.png.inc.c"
#include "effects/gfx/D_09000E00_351020.png.inc.c"
#include "effects/gfx/D_09001000_351220.png.inc.c"
#include "effects/gfx/D_09001200_351420.png.inc.c"
#include "effects/gfx/D_09001400_351620.png.inc.c"
#include "effects/gfx/D_09001600_351820.png.inc.c"
#include "effects/gfx/D_09001800_351A20.png.inc.c"
#include "effects/gfx/D_09001A00_351C20.png.inc.c"
#include "effects/gfx/D_09001C00_351E20.vtx.inc.c"
#include "effects/gfx/D_09001C10_351E30.vtx.inc.c"
#include "effects/gfx/D_09001C30_351E50.vtx.inc.c"
#include "effects/gfx/D_09001C40_351E60.vtx.inc.c"
#include "effects/gfx/D_09001C80_351EA0.vtx.inc.c"
#include "effects/gfx/D_09001CC0_351EE0.vtx.inc.c"
#include "effects/gfx/D_09001D00_351F20.vtx.inc.c"
#include "effects/gfx/D_09001D40_351F60.gfx.inc.c"
#include "effects/gfx/D_09001DE0_352000.gfx.inc.c"
#include "effects/gfx/D_09001E50_352070.gfx.inc.c"
#include "effects/gfx/D_09001E90_3520B0.gfx.inc.c"
#include "effects/gfx/D_09001ED0_3520F0.gfx.inc.c"
#include "effects/gfx/D_09001F10_352130.gfx.inc.c"
#include "effects/gfx/D_09001F50_352170.gfx.inc.c"
#include "effects/gfx/D_09001F90_3521B0.gfx.inc.c"
#include "effects/gfx/D_09001FD0_3521F0.gfx.inc.c"
#include "effects/gfx/D_09002010_352230.gfx.inc.c"
#include "effects/gfx/D_09002050_352270.gfx.inc.c"
#include "effects/gfx/D_09002090_3522B0.gfx.inc.c"
#include "effects/gfx/D_090020D0_3522F0.gfx.inc.c"
#include "effects/gfx/D_09002110_352330.gfx.inc.c"
#include "effects/gfx/D_09002150_352370.gfx.inc.c"
#include "effects/gfx/D_09002160_352380.gfx.inc.c"
#include "effects/gfx/D_09002170_352390.gfx.inc.c"
#include "effects/gfx/D_09002180_3523A0.gfx.inc.c"
#include "effects/gfx/D_09002190_3523B0.gfx.inc.c"
#include "effects/gfx/D_090021A8_3523C8.gfx.inc.c"
#include "effects/gfx/D_090021C0_3523E0.gfx.inc.c"
#include "effects/gfx/D_090021E0_352400.gfx.inc.c"
#include "effects/gfx/D_09002200_352420.gfx.inc.c"

8
src/effects/gfx/debuff.c Normal file
View File

@ -0,0 +1,8 @@
#include "common.h"
#include "effects/gfx/D_09000000_364C00.png.inc.c"
#include "effects/gfx/D_09000200_364E00.vtx.inc.c"
#include "effects/gfx/D_09000240_364E40.gfx.inc.c"
#include "effects/gfx/D_090002E8_364EE8.gfx.inc.c"

View File

@ -0,0 +1,40 @@
#include "common.h"
#include "effects/gfx/D_09000000_3863B0.png.inc.c"
#include "effects/gfx/D_09000200_3865B0.png.inc.c"
#include "effects/gfx/D_09000400_3867B0.png.inc.c"
#include "effects/gfx/D_09000600_3869B0.png.inc.c"
#include "effects/gfx/D_09000800_386BB0.png.inc.c"
#include "effects/gfx/D_09000A00_386DB0.png.inc.c"
#include "effects/gfx/D_09000C00_386FB0.png.inc.c"
#include "effects/gfx/D_09000E00_3871B0.png.inc.c"
#include "effects/gfx/D_09001000_3873B0.png.inc.c"
#include "effects/gfx/D_09001200_3875B0.png.inc.c"
#include "effects/gfx/D_09001400_3877B0.png.inc.c"
#include "effects/gfx/D_09001600_3879B0.png.inc.c"
#include "effects/gfx/D_09001800_387BB0.png.inc.c"
#include "effects/gfx/D_09002000_3883B0.vtx.inc.c"
#include "effects/gfx/D_09002040_3883F0.vtx.inc.c"
#include "effects/gfx/D_09002080_388430.vtx.inc.c"
#include "effects/gfx/D_090020C0_388470.vtx.inc.c"
#include "effects/gfx/D_09002100_3884B0.gfx.inc.c"
#include "effects/gfx/D_09002198_388548.gfx.inc.c"
#include "effects/gfx/D_09002230_3885E0.gfx.inc.c"
#include "effects/gfx/D_09002250_388600.gfx.inc.c"
#include "effects/gfx/D_09002270_388620.gfx.inc.c"
#include "effects/gfx/D_09002290_388640.gfx.inc.c"
#include "effects/gfx/D_090022B0_388660.gfx.inc.c"
#include "effects/gfx/D_09002320_3886D0.gfx.inc.c"
#include "effects/gfx/D_09002360_388710.gfx.inc.c"
#include "effects/gfx/D_090023A0_388750.gfx.inc.c"
#include "effects/gfx/D_090023E0_388790.gfx.inc.c"
#include "effects/gfx/D_09002420_3887D0.gfx.inc.c"
#include "effects/gfx/D_09002460_388810.gfx.inc.c"
#include "effects/gfx/D_090024A0_388850.gfx.inc.c"
#include "effects/gfx/D_090024E0_388890.gfx.inc.c"
#include "effects/gfx/D_09002520_3888D0.gfx.inc.c"
#include "effects/gfx/D_09002560_388910.gfx.inc.c"
#include "effects/gfx/D_090025A0_388950.gfx.inc.c"
#include "effects/gfx/D_090025E0_388990.gfx.inc.c"

View File

@ -0,0 +1,11 @@
#include "common.h"
#include "effects/gfx/D_09000000_330460.png.inc.c"
#include "effects/gfx/D_09000000_330460.pal.inc.c"
#include "effects/gfx/D_090000A0_330500.vtx.inc.c"
#include "effects/gfx/D_09000170_3305D0.vtx.inc.c"
#include "effects/gfx/D_09000230_330690.vtx.inc.c"
#include "effects/gfx/D_090002F0_330750.gfx.inc.c"
#include "effects/gfx/D_09000450_3308B0.gfx.inc.c"

View File

@ -0,0 +1,23 @@
#include "common.h"
#include "effects/gfx/D_09000000_32CEC0.png.inc.c"
#include "effects/gfx/D_09000000_32CEC0.pal.inc.c"
#include "effects/gfx/D_09000000_32CEC0.yellow.pal.inc.c"
#include "effects/gfx/D_090000C0_32CF80.png.inc.c"
#include "effects/gfx/D_090008C0_32D780.vtx.inc.c"
#include "effects/gfx/D_09000A30_32D8F0.vtx.inc.c"
#include "effects/gfx/D_09000A40_32D900.vtx.inc.c"
#include "effects/gfx/D_09000A50_32D910.vtx.inc.c"
#include "effects/gfx/D_09000A90_32D950.vtx.inc.c"
#include "effects/gfx/D_09000AB0_32D970.vtx.inc.c"
#include "effects/gfx/D_09000AF0_32D9B0.vtx.inc.c"
#include "effects/gfx/D_09000B50_32DA10.gfx.inc.c"
#include "effects/gfx/D_09000C10_32DAD0.gfx.inc.c"
#include "effects/gfx/D_09000CD0_32DB90.gfx.inc.c"
#include "effects/gfx/D_09000D58_32DC18.gfx.inc.c"
#include "effects/gfx/D_09000D90_32DC50.gfx.inc.c"
#include "effects/gfx/D_09000E08_32DCC8.gfx.inc.c"
#include "effects/gfx/D_09000E20_32DCE0.gfx.inc.c"
#include "effects/gfx/D_09000E38_32DCF8.gfx.inc.c"

View File

@ -0,0 +1,7 @@
#include "common.h"
#include "effects/gfx/D_09000000_32FB50.png.inc.c"
#include "effects/gfx/D_09000200_32FD50.vtx.inc.c"
#include "effects/gfx/D_09000240_32FD90.gfx.inc.c"

View File

@ -0,0 +1,17 @@
#include "common.h"
#include "effects/gfx/D_09000000_392440.png.inc.c"
#include "effects/gfx/D_09000080_3924C0.png.inc.c"
#include "effects/gfx/D_09000100_392540.png.inc.c"
#include "effects/gfx/D_09000180_3925C0.png.inc.c"
#include "effects/gfx/D_09000200_392640.png.inc.c"
#include "effects/gfx/D_09000280_3926C0.vtx.inc.c"
#include "effects/gfx/D_090002C0_392700.gfx.inc.c"
#include "effects/gfx/D_09000330_392770.gfx.inc.c"
#include "effects/gfx/D_09000370_3927B0.gfx.inc.c"
#include "effects/gfx/D_090003B0_3927F0.gfx.inc.c"
#include "effects/gfx/D_090003F0_392830.gfx.inc.c"
#include "effects/gfx/D_09000430_392870.gfx.inc.c"
#include "effects/gfx/D_09000470_3928B0.gfx.inc.c"

View File

@ -0,0 +1,11 @@
#include "common.h"
#include "effects/gfx/D_09000000_330F00.png.inc.c"
#include "effects/gfx/D_09000080_330F80.png.inc.c"
#include "effects/gfx/D_09000880_331780.vtx.inc.c"
#include "effects/gfx/D_090008C0_3317C0.vtx.inc.c"
#include "effects/gfx/D_09000900_331800.gfx.inc.c"
#include "effects/gfx/D_090009E8_3318E8.gfx.inc.c"
#include "effects/gfx/D_09000A10_331910.gfx.inc.c"

View File

@ -0,0 +1,20 @@
#include "common.h"
#include "effects/gfx/D_09000000_3CFAF0.png.inc.c"
#include "effects/gfx/D_09000000_3CFAF0.pal.inc.c"
u8 D_09000220_3CFD10[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
#include "effects/gfx/D_09000400_3CFEF0.png.inc.c"
#include "effects/gfx/D_09000400_3CFEF0.pal.inc.c"
u8 D_09000620_3D0110[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
#include "effects/gfx/D_09000800_3D02F0.gfx.inc.c"
#include "effects/gfx/D_090008D8_3D03C8.gfx.inc.c"
#include "effects/gfx/D_090009B0_3D04A0.vtx.inc.c"
#include "effects/gfx/D_090009F0_3D04E0.gfx.inc.c"

View File

@ -1,15 +1,15 @@
#include "common.h"
#include "effects_internal.h"
extern Gfx D_090002C0[];
extern Gfx D_09000330[];
extern Gfx D_09000370[];
extern Gfx D_090003B0[];
extern Gfx D_090003F0[];
extern Gfx D_09000430[];
extern Gfx D_09000470[];
extern Gfx D_090002C0_392700[];
extern Gfx D_09000330_392770[];
extern Gfx D_09000370_3927B0[];
extern Gfx D_090003B0_3927F0[];
extern Gfx D_090003F0_392830[];
extern Gfx D_09000430_392870[];
extern Gfx D_09000470_3928B0[];
static Gfx* sDlists[] = { D_09000430, D_090003F0, D_090003B0, D_09000370, D_09000330 };
static Gfx* sDlists[] = { D_09000430_392870, D_090003F0_392830, D_090003B0_3927F0, D_09000370_3927B0, D_09000330_392770 };
static s32 sPartParams[4 * 5] = {
1, 0, 0, 0, 100,
@ -126,7 +126,7 @@ void small_gold_sparkle_appendGfx(void* effect) {
shim_guMtxF2L(sp18, &gDisplayContext->matrixStack[gMatrixListPos]);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_090002C0);
gSPDisplayList(gMasterGfxPos++, D_090002C0_392700);
gDPSetPrimColor(gMasterGfxPos++, 0, 0, 255, 255, 15, 255);
part++;
@ -144,7 +144,7 @@ void small_gold_sparkle_appendGfx(void* effect) {
G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPMatrix(gMasterGfxPos++, spD8, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, sDlists[part->unk_04 >> 1]);
gSPDisplayList(gMasterGfxPos++, D_09000470);
gSPDisplayList(gMasterGfxPos++, D_09000470_3928B0);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}
}

View File

@ -3,8 +3,8 @@
s32 D_E001C5E0 = 0;
extern Gfx D_09000900[];
extern Gfx D_090009E8[];
extern Gfx D_09000900_331800[];
extern Gfx D_090009E8_3318E8[];
void snowflake_init(EffectInstance* effect);
void snowflake_update(EffectInstance* effect);
@ -124,7 +124,7 @@ void snowflake_appendGfx(void* effect) {
gDPPipeSync(gMasterGfxPos++);
gSPSegment(gMasterGfxPos++, 0x09, VIRTUAL_TO_PHYSICAL(effectTemp->graphics->data));
gSPDisplayList(gMasterGfxPos++, D_09000900);
gSPDisplayList(gMasterGfxPos++, D_09000900_331800);
shim_guTranslateF(sp18, part->xPos, part->yPos, part->zPos);
shim_guRotateF(spD8, -gCameras[gCurrentCameraID].currentYaw, 0.0f, 1.0f, 0.0f);
@ -140,7 +140,7 @@ void snowflake_appendGfx(void* effect) {
shim_guMtxF2L(sp118, &gDisplayContext->matrixStack[gMatrixListPos]);
gSPMatrix(gMasterGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(gMasterGfxPos++, D_090009E8);
gSPDisplayList(gMasterGfxPos++, D_090009E8_3318E8);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}

View File

@ -8,11 +8,11 @@ void throw_spiny_init(EffectInstance* effect);
void throw_spiny_update(EffectInstance* effect);
void throw_spiny_render(EffectInstance* effect);
extern Gfx D_09000800[];
extern Gfx D_090008D8[];
extern Gfx D_090009F0[];
extern Gfx D_09000800_3D02F0[];
extern Gfx D_090008D8_3D03C8[];
extern Gfx D_090009F0_3D04E0[];
Gfx* D_E00C8710[2] = { D_09000800, D_090008D8 };
Gfx* D_E00C8710[2] = { D_09000800_3D02F0, D_090008D8_3D03C8 };
u8 D_E00C8718[8] = { 110, 150, 130, 110, 100, 95, 100, 0 };
u8 D_E00C8720[8] = { 80, 60, 80, 100, 120, 110, 100, 0 };
@ -207,6 +207,6 @@ void throw_spiny_appendGfx(void* effect) {
gSPMatrix(gMasterGfxPos++, camera->unkMatrix, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gDPSetPrimColor(gMasterGfxPos++, 0, 0, data->unk_30, data->unk_34, data->unk_38, temp_s5);
gSPDisplayList(gMasterGfxPos++, D_E00C8710[temp_s6]);
gSPDisplayList(gMasterGfxPos++, D_090009F0);
gSPDisplayList(gMasterGfxPos++, D_090009F0_3D04E0);
gSPPopMatrix(gMasterGfxPos++, G_MTX_MODELVIEW);
}

View File

@ -230,7 +230,7 @@ Gfx gPauseDLArrows[] = {
gsDPSetTextureFilter(G_TF_POINT),
gsDPSetTextureConvert(G_TC_FILT),
gsDPSetTextureLUT(G_TT_NONE),
gsDPLoadTextureTile_4b(pause_map_arrows_png, G_IM_FMT_IA, pause_map_arrows_png_width, pause_map_arrows_png_height, 0, 0, pause_map_arrows_png_width - 1, pause_map_arrows_png_height - 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 6, G_TX_NOLOD, G_TX_NOLOD),
gsDPLoadTextureTile_4b(pause_arrows_png, G_IM_FMT_IA, pause_arrows_png_width, pause_arrows_png_height, 0, 0, pause_arrows_png_width - 1, pause_arrows_png_height - 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 6, G_TX_NOLOD, G_TX_NOLOD),
gsDPSetRenderMode(AA_EN | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM), AA_EN | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)),
gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA),
gsSPClearGeometryMode(G_LIGHTING),

View File

@ -8,15 +8,15 @@
s32 D_80077980[] = { &D_8038F800, &D_803B5000, &heap_battleHead, };
NUPiOverlaySegment D_8007798C = {
.romStart = _163400_ROM_START,
.romEnd = _163400_ROM_END,
.ramStart = _163400_VRAM,
.textStart = _163400_TEXT_START,
.textEnd = _163400_TEXT_END,
.dataStart = _163400_DATA_START,
.dataEnd = _163400_DATA_END,
.bssStart = _163400_BSS_START,
.bssEnd = _163400_BSS_END,
.romStart = filemenu_ROM_START,
.romEnd = filemenu_ROM_END,
.ramStart = filemenu_VRAM,
.textStart = filemenu_TEXT_START,
.textEnd = filemenu_TEXT_END,
.dataStart = filemenu_DATA_START,
.dataEnd = filemenu_DATA_END,
.bssStart = filemenu_BSS_START,
.bssEnd = filemenu_BSS_END,
};
u8 D_800779B0 = 0;

View File

@ -1,19 +1,11 @@
#! /usr/bin/python3
from pathlib import Path
from sys import argv
import re
import png
if __name__ == "__main__":
infile, outfile = argv[1:]
cname = re.sub(r"[^0-9a-zA-Z_]", "_", outfile)
if cname.startswith("ver_"):
cname = "_".join(cname.split("_")[2:])
cname = re.sub(r"^build_include_", "", cname)
cname = re.sub(r"_inc_c$", "", cname)
infile, outfile, cname = argv[1:]
with open(outfile, "w") as f:
f.write(f"unsigned char {cname}[] = {{")

View File

@ -140,12 +140,12 @@ def write_ninja_rules(ninja: ninja_syntax.Writer, cpp: str, cppflags: str, extra
ninja.rule("img_header",
description="img_header $in",
command=f"$python {BUILD_TOOLS}/img/header.py $in $out",
command=f"$python {BUILD_TOOLS}/img/header.py $in $out $c_name",
)
ninja.rule("bin_inc_c",
description="bin_inc_c $out",
command=f"$python {BUILD_TOOLS}/bin_inc_c.py $in $out",
command=f"$python {BUILD_TOOLS}/bin_inc_c.py $in $out $c_name",
)
ninja.rule("yay0",
@ -231,7 +231,7 @@ class Configure:
modes = ["ld"]
if assets:
modes.extend(["bin", "Yay0", "img", "vtx", "pm_map_data", "pm_msg", "pm_npc_sprites", "pm_charset",
modes.extend(["bin", "Yay0", "img", "vtx", "gfx", "pm_map_data", "pm_msg", "pm_npc_sprites", "pm_charset",
"pm_charset_palettes", "pm_effect_loads", "pm_effect_shims"])
if code:
modes.extend(["code", "c", "data", "rodata"])
@ -409,8 +409,12 @@ class Configure:
"img_flags": flags,
})
build(inc_dir / (seg.name + ".png.h"), src_paths, "img_header")
build(inc_dir / (seg.name + ".png.inc.c"), [bin_path], "bin_inc_c")
c_sym = seg.create_symbol(
addr=seg.vram_start, in_segment=True, type="data", define=True
)
vars = {"c_name": c_sym.name}
build(inc_dir / (seg.name + ".png.h"), src_paths, "img_header", vars)
build(inc_dir / (seg.name + ".png.inc.c"), [bin_path], "bin_inc_c", vars)
elif isinstance(seg, segtypes.n64.palette.N64SegPalette):
src_paths = [seg.out_path().relative_to(ROOT)]
inc_dir = self.build_path() / "include" / seg.dir
@ -420,7 +424,12 @@ class Configure:
"img_type": seg.type,
"img_flags": "",
})
build(inc_dir / (seg.name + ".pal.inc.c"), [bin_path], "bin_inc_c")
c_sym = seg.create_symbol(
addr=seg.vram_start, in_segment=True, type="data", define=True
)
vars = {"c_name": c_sym.name}
build(inc_dir / (seg.name + ".pal.inc.c"), [bin_path], "bin_inc_c", vars)
elif isinstance(seg, segtypes.common.bin.CommonSegBin):
build(entry.object_path, entry.src_paths, "bin")
elif isinstance(seg, segtypes.n64.Yay0.N64SegYay0):
@ -443,6 +452,10 @@ class Configure:
})
build(entry.object_path, [bin_path], "bin")
# c_sym = seg.create_symbol(
# addr=seg.vram_start, in_segment=True, type="data", define=True
# )
# vars = {"c_name": c_sym.name}
build(inc_dir / (seg.name + ".png.h"), entry.src_paths, "img_header")
elif isinstance(seg, segtypes.n64.palette.N64SegPalette):
bin_path = entry.object_path.with_suffix(".bin")

View File

@ -5,21 +5,24 @@ import re
import png
if __name__ == "__main__":
infile, outfile = argv[1:]
infile, outfile = argv[1:3]
if len(argv) > 3:
cname = argv[3]
else:
cname = re.sub(r"[^0-9a-zA-Z_]", "_", infile)
if cname.startswith("ver_"):
cname = "_".join(cname.split("_")[2:])
if cname.startswith("src_"):
cname = cname[4:]
elif cname.startswith("assets_"):
cname = "_".join(cname.split("_")[2:])
img = png.Reader(infile)
width, height, rows, info = img.read()
cname = re.sub(r"[^0-9a-zA-Z_]", "_", infile)
if cname.startswith("ver_"):
cname = "_".join(cname.split("_")[2:])
if cname.startswith("src_"):
cname = cname[4:]
elif cname.startswith("assets_"):
cname = "_".join(cname.split("_")[2:])
with open(outfile, "w") as f:
f.write("// Generated file, do not edit.\n")
f.write(f"#ifndef _{cname.upper()}_\n")

View File

@ -10,10 +10,10 @@ jobs:
name: mypy
steps:
- uses: actions/checkout@v1
- name: Set up Python 3.9
- name: Set up Python 3.8
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: 3.8
- name: Install Dependencies
run: |
pip install mypy

View File

@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/ethteck/splat.git
branch = master
commit = a847090eac32ef0d9cf183cd8f04e2452a0e250b
parent = 3e71bb8cea31e9e5a87f2f251e99d55daa0f902e
commit = aa71299594b8f864f9af9c22823c64a9c9189706
parent = d0b02e98a6bf6773e3c4f4ca7f1e203c86aaf6df
method = merge
cmdver = 0.4.3

View File

@ -1,5 +1,65 @@
# splat Release Notes
## 0.9.0: The Big Update
### Introducing [spimdisasm](https://github.com/Decompollaborate/spimdisasm)!
* Thanks to [AngheloAlf](https://github.com/AngheloAlf), we now have a much better MIPS disassembler in splat! spimdisasm has much better hi/lo matching, much lower ram usage, and plenty of other goodies.
We plan to roll this out in phases. Currently, it only handles actual code disassembly. Later on, we will probably migrate our current data assembly code to use spimdisasm as well.
**NOTICE**: This integration has been tested on a variety of games and configurations. However, with any giant change to the platform like this, there are bound to be things we didn't catch. Please be patient with us as we handle these remaining issues. Though from what we've seen already, the slight bugs one may come across are totally worth the much improved disassembly.
### gfx segment type
* A new `gfx` segment type is available, which creates a c file containing a disassembled display list according to the segment's start and end offsets. Thanks to [Glank](https://github.com/glankk) and [Tharo](https://github.com/thar0/) for their work on [libgfxd](https://github.com/glankk/libgfxd) and [pygfxd](https://github.com/thar0/pygfxd/), respectively, for helping make this a possibility in splat.
### API breaking changes
* Some `Segment()` arguments have changed, which may cause extensions to break. Please see the `__init__` function for `Segment` for more details.
### symbol_addrs.txt changes
* symbol_addrs now supports the `segment:` attribute, which allows specifying the symbol's top-level segment. This can be helpful for symbol resolution when overlays use overlapping vram ranges. See `exclusive_ram_id` below for more information.
### Global options changes
The new `symbol_name_format` option allows specification of how symbols will be named. This can be set as a global option and also changed per-segment. `symbol_norom_name_format` is used when the symbol does not have a rom address (BSS).
The following substitutions are allowed:
`$ROM` - the rom address of the symbol, hex-formatted and padded to 6 characters (ABCF10, 000030, 123456) (note: only for `symbol_name_format`, usage in `symbol_norom_name_format` will cause an error)
`$VRAM` - the vram address of the symbol, hex-formatted and padded to 8 characters (00030010, 00020015, ABCDEF10)
`$SEG` - the name of the top-level segment in which the symbol resides
The default values for these options are as follows
`symbol_name_format` : `$VRAM_$ROM`
`symbol_noram_name_format` : `$VRAM_$SEG`
The appropriate prefix string will still automatically be applied depending on the type of the symbol: `D_` for data, `jtbl_` for jump tables, and `func_` for functions. This functionality may be customizable in the future.
----
The `auto_all_section` option now should be a list of section names (`[".data", ".rodata", ".bss"]` by default) indicating the sections that should be linked from .o files built from source files (.c or asm/hasm .s files), when no subsegment explicitly indicates linking this type of section.
For example, if any subsegment of a code segment is of segment type `data` or `.data`, the `.data` section from all `c`/`asm`/`hasm` subsegments will not be linked unless explicitly indicated with a relevant `.data` subsegment.
Previously, this option was a bool, and it enabled this feature for all sections specified in `section_order`. Now, the desired sections must be specified manually. The default value for this option retains previous behavior.
----
The new `mips_abi_float_regs` option allows for changing the format of float registers for MIPS disassembly. The default value does not change any prior behavior, but `o32` is heavily encouraged and may become the default option in the future. For more information, see this [great writeup](https://gist.github.com/EllipticEllipsis/27eef11205c7a59d8ea85632bc49224d).
----
The new `gfx_ucode` option allows for specifying the target for the graphics macro format, which is used in the gfx segment type. The default is `f3dex2`.
### Segment options changes
The new `exclusive_ram_id` segment option allows specifying an identifer that will prevent the segment from seeing any symbols from other segments with the same identifer. This is useful when multiple segments are mapped to the same vram address at runtime and should never be able to refer to each other's symbols. Setting all of these segments to have the same value for this option will prevent their symbols from clashing / meshing unexpectedly.
----
The `overlay` setting on segments has been removed. Please see `symbol_name_format` above for info on how to influence the names of symbols, which can be applied at the segment level as well as the global level.
----
## 0.8.0: Arbitrary Section Order
* You can now use the option `section_order` to define the binary section order for your target binary. By default, this is `[".text", ".data", ".rodata", ".bss"]`. See options.py for more details
* Documented all options in options.py
@ -30,7 +90,7 @@
* Fixed a bug involving detection of defined functions in c files for GLOBAL_ASM-using projects
* Added options to disable the creation of undefined_funcs/syms_auto.txt files
* Add a Vtx segment type for creating c files containg model vertex data in the n64 libultra Vtx format
* Added a Vtx segment type for creating c files containg model vertex data in the n64 libultra Vtx format
* Added a `cpp` segment type which is identical to `c` but looks for a file with the extension ".cpp" instead of ".c".
### 0.7.5: all_ types and auto_all_sections

View File

@ -3,9 +3,7 @@ A binary splitting tool to assist with decompilation and modding projects
Currently, only N64 and PSX binaries are supported.
The Makefile `setup` target calls splat with a config file that you can use for reference.
Please check out the [wiki](https://github.com/ethteck/splat/wiki) for more information including [examples](https://github.com/ethteck/splat/wiki/Examples) of projects that use splat.
### Requirements
Python package requirements can be installed via `pip3 install -r requirements.txt`
splat requires Python 3.8+. Package requirements can be installed via `pip3 install -r requirements.txt`

View File

@ -1,5 +1,6 @@
#! /usr/bin/env python3
import sys
import argparse
from pathlib import Path
@ -9,11 +10,17 @@ parser = argparse.ArgumentParser(description="Create a splat config from an N64
parser.add_argument("rom", help="Path to a .z64/.n64 ROM")
def main(rom_path):
rom = rominfo.get_info(rom_path)
def main(rom_path: Path):
if not rom_path.exists():
sys.exit(f"ROM file {rom_path} does not exist ({rom_path.absolute()})")
if rom_path.is_dir():
sys.exit(f"Path {rom_path} is a directory ({rom_path.absolute()})")
rom_bytes = rominfo.read_rom(rom_path)
rom = rominfo.get_info(rom_path, rom_bytes)
basename = rom.name.replace(" ", "").lower()
header = f"""
header = f"""\
name: {rom.name.title()} ({rom.get_country_name()})
sha1: {rom.sha1}
options:
@ -24,7 +31,9 @@ options:
find_file_boundaries: True
header_encoding: {rom.header_encoding}
# platform: n64
# undefined_funcs_auto: True
# undefined_funcs_auto_path: undefined_funcs_auto.txt
# undefined_syms_auto: True
# undefined_syms_auto_path: undefined_syms_auto.txt
# symbol_addrs_path: symbol_addrs.txt
# undefined_syms_path: undefined_syms.txt
@ -32,15 +41,14 @@ options:
# src_path: src
# build_path: build
# extensions_path: tools/splat_ext
# auto_all_sections: True
""".lstrip()
# mips_abi_float_regs: o32
# section_order: [".text", ".data", ".rodata", ".bss"]
# auto_all_sections: [".data", ".rodata", ".bss"]
"""
with open(rom_path, "rb") as f:
fbytes = f.read()
first_section_end = find_code_length.run(rom_bytes, 0x1000, rom.entry_point)
first_section_end = find_code_length.run(fbytes, 0x1000, rom.entry_point)
segments = f"""
segments = f"""\
segments:
- name: header
type: header
@ -57,12 +65,13 @@ segments:
- type: bin
start: 0x{first_section_end:X}
- [0x{rom.size:X}]
""".lstrip()
"""
out_file = f"{basename}.yaml"
with open(out_file, "w", newline="\n") as f:
print(f"Writing config to {out_file}")
f.write(header + segments)
f.write(header)
f.write(segments)
if __name__ == "__main__":

View File

@ -1,3 +1,3 @@
[mypy]
ignore_missing_imports = True
mypy_path = stubs
mypy_path = stubs

View File

@ -2,4 +2,8 @@ PyYAML
pylibyaml
pypng
colorama
capstone
spimdisasm>=1.2.1
rabbitizer
pygfxd
tqdm
intervaltree

View File

@ -15,7 +15,7 @@ class CommonSegAsm(CommonSegCodeSubsegment):
and self.rom_end != "auto"
and self.rom_start != self.rom_end
):
self.funcs_text = self.scan_code(rom_bytes, is_asm=True)
self.scan_code(rom_bytes, is_asm=True)
def get_file_header(self):
return []
@ -26,16 +26,9 @@ class CommonSegAsm(CommonSegCodeSubsegment):
if out_path:
out_path.parent.mkdir(parents=True, exist_ok=True)
out_lines = self.get_file_header()
self.print_file_boundaries()
self.funcs_text = self.split_code(rom_bytes)
for func in self.funcs_text:
out_lines.extend(self.funcs_text[func][0])
out_lines.append("")
self.split_write(out_path, out_lines)
def split_write(self, out_path, out_lines):
with open(out_path, "w", newline="\n") as f:
f.write("\n".join(out_lines))
with open(out_path, "w", newline="\n") as f:
for line in self.get_file_header():
f.write(line + "\n")
f.write(self.text_section.disassemble())

View File

@ -1,6 +1,9 @@
from segtypes.common.data import CommonSegData
from segtypes.linker_entry import LinkerEntry
from util import options, log
from typing import List
class CommonSegBss(CommonSegData):
def get_linker_section(self) -> str:
@ -12,12 +15,14 @@ class CommonSegBss(CommonSegData):
def split(self, rom_bytes: bytes):
pass
def get_linker_entries(self):
from segtypes.linker_entry import LinkerEntry
def get_linker_entries(self) -> "List[LinkerEntry]":
if self.sibling:
path = self.sibling.out_path()
else:
path = options.get_src_path() / self.name
path = self.out_path()
return [LinkerEntry(self, [path], path, self.get_linker_section())]
if path:
return [LinkerEntry(self, [path], path, self.get_linker_section())]
else:
return []

View File

@ -4,6 +4,8 @@ from typing import Optional, Set
import os
import re
from pathlib import Path
import spimdisasm
import rabbitizer
from util import log, options
from util.compiler import GCC, SN64
@ -122,26 +124,25 @@ class CommonSegC(CommonSegCodeSubsegment):
asm_out_dir = options.get_nonmatchings_path() / self.dir
asm_out_dir.mkdir(parents=True, exist_ok=True)
is_new_c_file = False
self.print_file_boundaries()
self.funcs_text = self.split_code(rom_bytes)
is_new_c_file = False
c_path = self.out_path()
if c_path:
if not os.path.exists(c_path) and options.get_create_c_files():
self.create_c_file(self.funcs_text, asm_out_dir, c_path)
self.create_c_file(asm_out_dir, c_path)
is_new_c_file = True
for func_addr in self.funcs_text:
func_sym = self.parent.get_symbol(
func_addr, type="func", local_only=True
for func in self.text_section.symbolList:
assert func.vram is not None
func_sym = self.get_symbol(
func.vram, in_segment=True, type="func", local_only=True
)
assert func_sym is not None
if func_sym.name in self.global_asm_funcs or is_new_c_file:
self.create_c_asm_file(
self.funcs_text, func_addr, asm_out_dir, func_sym
)
if func.getName() in self.global_asm_funcs or is_new_c_file:
self.create_c_asm_file(func, asm_out_dir, func_sym)
def get_c_preamble(self):
ret = []
@ -155,8 +156,8 @@ class CommonSegC(CommonSegCodeSubsegment):
def mark_c_funcs_as_defined(self, c_funcs):
for func_name in c_funcs:
found = False
for func_addr in self.seg_symbols:
for symbol in self.seg_symbols[func_addr]:
for symbols in self.seg_symbols.values():
for symbol in symbols:
if symbol.name == func_name:
symbol.defined = True
found = True
@ -164,8 +165,11 @@ class CommonSegC(CommonSegCodeSubsegment):
if found:
break
def create_c_asm_file(self, funcs_text, func_addr, out_dir, func_sym: Symbol):
def create_c_asm_file(
self, func: spimdisasm.mips.symbols.SymbolBase, out_dir, func_sym: Symbol
):
outpath = Path(os.path.join(out_dir, self.name, func_sym.name + ".s"))
assert func.vram is not None
# Skip extraction if the file exists and the symbol is marked as extract=false
if outpath.exists() and not func_sym.extract:
@ -179,10 +183,10 @@ class CommonSegC(CommonSegCodeSubsegment):
if self.parent and isinstance(self.parent, CommonSegGroup):
if (
options.get_migrate_rodata_to_functions()
and func_addr in self.parent.rodata_syms
and func.vram in self.parent.rodata_syms
):
func_rodata = list(
{s for s in self.parent.rodata_syms[func_addr] if s.disasm_str}
{s for s in self.parent.rodata_syms[func.vram] if s.disasm_str}
)
func_rodata.sort(key=lambda s: s.vram_start)
@ -205,8 +209,7 @@ class CommonSegC(CommonSegCodeSubsegment):
out_lines.append(".section .text")
out_lines.append("")
out_lines.extend(funcs_text[func_addr][0])
out_lines.append("")
out_lines.append(func.disassemble())
outpath.parent.mkdir(parents=True, exist_ok=True)
@ -215,21 +218,19 @@ class CommonSegC(CommonSegCodeSubsegment):
f.write(newline_sep.join(out_lines))
self.log(f"Disassembled {func_sym.name} to {outpath}")
def create_c_file(self, funcs_text, asm_out_dir, c_path):
def create_c_file(self, asm_out_dir, c_path):
c_lines = self.get_c_preamble()
for func in funcs_text:
func_name = self.parent.get_symbol(func, type="func", local_only=True).name
for func in self.text_section.symbolList:
assert isinstance(func, spimdisasm.mips.symbols.SymbolFunction)
# Terrible hack to "auto-decompile" empty functions
# TODO move disassembly into funcs_text or somewhere we can access it from here
if (
options.get_auto_decompile_empty_functions()
and len(funcs_text[func][0]) == 3
and funcs_text[func][0][1][-3:] in ["$ra", "$31"]
and funcs_text[func][0][2][-3:] == "nop"
and func.instructions[0].isJrRa()
and func.instructions[1].isNop()
):
c_lines.append("void " + func_name + "(void) {")
c_lines.append("void " + func.getName() + "(void) {")
c_lines.append("}")
else:
if options.get_compiler() in [GCC, SN64]:
@ -237,12 +238,16 @@ class CommonSegC(CommonSegCodeSubsegment):
rel_asm_out_dir = asm_out_dir.relative_to(
options.get_nonmatchings_path()
)
c_lines.append(f'INCLUDE_ASM(s32, "{rel_asm_out_dir / self.name}", {func_name});')
c_lines.append(
f'INCLUDE_ASM(s32, "{rel_asm_out_dir / self.name}", {func.getName()});'
)
else:
c_lines.append(f'INCLUDE_ASM("{asm_out_dir / self.name}", {func_name});')
c_lines.append(
f'INCLUDE_ASM("{asm_out_dir / self.name}", {func.getName()});'
)
else:
asm_outpath = Path(
os.path.join(asm_out_dir, self.name, func_name + ".s")
os.path.join(asm_out_dir, self.name, func.getName() + ".s")
)
rel_asm_outpath = os.path.relpath(
asm_outpath, options.get_base_path()

View File

@ -1,7 +1,15 @@
from typing import Dict, Tuple
from collections import OrderedDict
from typing import Dict, List, Optional, Tuple
import typing
from segtypes.common.group import CommonSegGroup
from segtypes.common.linker_section import dotless_type
from segtypes.segment import RomAddr, Segment
from util import log, options
from util.range import Range
from util.symbols import Symbol
CODE_TYPES = ["c", "asm", "hasm"]
# code group
class CommonSegCode(CommonSegGroup):
def __init__(
@ -13,11 +21,15 @@ class CommonSegCode(CommonSegGroup):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
self.bss_size: int = yaml.get("bss_size", 0) if isinstance(yaml, dict) else 0
super().__init__(
rom_start,
rom_end,
@ -26,30 +38,295 @@ class CommonSegCode(CommonSegGroup):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.reported_file_split = False
self.labels_to_add = set()
self.jtbl_glabels_to_add = set()
self.jtbl_jumps = {}
self.jumptables: Dict[int, Tuple[int, int]] = {}
self.rodata_syms: Dict[int, List[Symbol]] = {}
@property
def needs_symbols(self) -> bool:
return True
@property
def vram_end(self) -> Optional[int]:
if self.vram_start is not None and self.size is not None:
return self.vram_start + self.size + self.bss_size
else:
return None
# def ram_to_rom(self, ram_addr: int) -> Optional[int]:
# size_no_bss = self.vram_start + self.size
# # Do not return a rom address if this is a BSS symbol
# if ram_addr > size_no_bss:
# return None
# if not self.contains_vram(ram_addr) and ram_addr != self.vram_end:
# return None
# if self.vram_start is not None and isinstance(self.rom_start, int):
# return self.rom_start + ram_addr - self.vram_start
# else:
# return None
# Prepare symbol for migration to the function
def check_rodata_sym(self, func_addr: int, sym: Symbol):
if self.section_boundaries[".rodata"].is_complete():
if (
self.section_boundaries[".rodata"].start
<= sym.vram_start
< self.section_boundaries[".rodata"].end
):
assert self.section_boundaries[".rodata"].start is not None
assert self.section_boundaries[".rodata"].end is not None
rodata_start: int = self.section_boundaries[".rodata"].start
rodata_end: int = self.section_boundaries[".rodata"].end
if rodata_start <= sym.vram_start < rodata_end:
if func_addr not in self.rodata_syms:
self.rodata_syms[func_addr] = []
self.rodata_syms[func_addr].append(sym)
def handle_alls(self, segs: List[Segment], base_segs) -> bool:
for i, elem in enumerate(segs):
if elem.type.startswith("all_"):
alls = []
rep_type = f"{elem.type[4:]}"
replace_class = Segment.get_class_for_type(rep_type)
for base in base_segs.items():
if isinstance(elem.rom_start, int) and isinstance(
self.rom_start, int
):
# Shoddy rom to ram
vram_start = elem.rom_start - self.rom_start + self.vram_start
else:
vram_start = "auto"
rep: Segment = replace_class(
rom_start=elem.rom_start,
rom_end=elem.rom_end,
type=rep_type,
name=base[0],
vram_start=vram_start,
extract=False,
given_subalign=self.given_subalign,
exclusive_ram_id=self.get_exclusive_ram_id(),
given_dir=self.given_dir,
symbol_name_format=self.symbol_name_format,
symbol_name_format_no_rom=self.symbol_name_format_no_rom,
args=[],
yaml={},
)
rep.sibling = base[1]
rep.parent = self
alls.append(rep)
# Insert alls into segs at i
del segs[i]
segs[i:i] = alls
return True
return False
# Find places we should automatically add "all_data" / "all_rodata" / "all_bss"
def find_inserts(
self, found_sections: typing.OrderedDict[str, Range]
) -> "OrderedDict[str, int]":
inserts: OrderedDict[str, int] = OrderedDict()
section_order = self.section_order.copy()
section_order.remove(".text")
for i, section in enumerate(section_order):
if section not in options.auto_all_sections():
continue
if not found_sections[section].has_start():
search_done = False
for j in range(i - 1, -1, -1):
end = found_sections[section_order[j]].end
if end is not None:
inserts[section] = end
search_done = True
break
if not search_done:
inserts[section] = -1
pass
return inserts
def parse_subsegments(self, segment_yaml) -> List[Segment]:
base_segments: OrderedDict[str, Segment] = OrderedDict()
ret = []
prev_start: RomAddr = -1
inserts: OrderedDict[
str, int
] = (
OrderedDict()
) # Used to manually add "all_" types for sections not otherwise defined in the yaml
self.section_boundaries = OrderedDict(
(s_name, Range()) for s_name in options.get_section_order()
)
found_sections = OrderedDict(
(s_name, Range()) for s_name in self.section_boundaries
) # Stores yaml index where a section was first found
found_sections.pop(".text")
if "subsegments" not in segment_yaml:
return []
# Mark any manually added dot types
cur_section = None
for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
# rompos marker
if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
continue
typ = Segment.parse_segment_type(subsection_yaml)
if typ.startswith("all_"):
typ = typ[4:]
if not typ.startswith("."):
typ = f".{typ}"
if typ in found_sections:
if cur_section is None:
# Starting point
found_sections[typ].start = i
cur_section = typ
else:
if cur_section != typ:
# We're changing sections
if found_sections[cur_section].has_end():
log.error(
f"Section {cur_section} end encountered but was already ended earlier!"
)
if found_sections[typ].has_start():
log.error(
f"Section {typ} start encounted but has already started earlier!"
)
# End the current section
found_sections[cur_section].end = i
# Start the next section
found_sections[typ].start = i
cur_section = typ
if cur_section is not None:
found_sections[cur_section].end = -1
inserts = self.find_inserts(found_sections)
for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
# rompos marker
if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
continue
typ = Segment.parse_segment_type(subsection_yaml)
start = Segment.parse_segment_start(subsection_yaml)
# Add dummy segments to be expanded later
if typ.startswith("all_"):
ret.append(Segment(start, "auto", typ, "", "auto"))
continue
segment_class = Segment.get_class_for_type(typ)
end = self.get_next_seg_start(i, segment_yaml["subsegments"])
if (
isinstance(start, int)
and isinstance(prev_start, int)
and start < prev_start
):
log.error(
f"Error: Group segment {self.name} contains subsegments which are out of ascending rom order (0x{prev_start:X} followed by 0x{start:X})"
)
vram = None
if start != "auto":
assert isinstance(start, int)
vram = self.get_most_parent().rom_to_ram(start)
segment: Segment = Segment.from_yaml(
segment_class, subsection_yaml, start, end, vram
)
segment.sibling = base_segments.get(segment.name, None)
segment.parent = self
for i, section in enumerate(self.section_order):
if not self.section_boundaries[section].has_start() and dotless_type(
section
) == dotless_type(segment.type):
if i > 0:
prev_section = self.section_order[i - 1]
self.section_boundaries[prev_section].end = segment.vram_start
self.section_boundaries[section].start = segment.vram_start
ret.append(segment)
# todo change
if typ in CODE_TYPES:
base_segments[segment.name] = segment
prev_start = start
# Add the automatic all_ sections
orig_len = len(ret)
for section in reversed(inserts):
idx = inserts[section]
if idx == -1:
idx = orig_len
# bss hack TODO maybe rethink
if section == "bss" and self.vram_start is not None:
rom_start = self.rom_end
vram_start = self.vram_start + self.rom_end - self.rom_start
else:
rom_start = "auto"
vram_start = "auto"
ret.insert(
idx,
(
Segment(
rom_start,
"auto",
"all_" + section,
"",
vram_start,
)
),
)
check = True
while check:
check = self.handle_alls(ret, base_segments)
# TODO why is this necessary?
if (
self.section_boundaries[".rodata"].has_start()
and not self.section_boundaries[".rodata"].has_end()
):
assert self.vram_end is not None
self.section_boundaries[".rodata"].end = self.vram_end
return ret
def scan(self, rom_bytes):
# Always scan code first
for sub in self.subsegments:
if sub.type in CODE_TYPES and sub.should_scan():
sub.scan(rom_bytes)
# Scan everyone else
for sub in self.subsegments:
if sub.type not in CODE_TYPES and sub.should_scan():
sub.scan(rom_bytes)

View File

@ -1,77 +1,39 @@
from dataclasses import dataclass
from typing import List, Optional
import typing
from util import options
from segtypes.common.code import CommonSegCode
from collections import OrderedDict
import re
from capstone import (
Cs,
CS_ARCH_MIPS,
CS_MODE_MIPS64,
CS_MODE_BIG_ENDIAN,
CS_MODE_MIPS32,
CS_MODE_LITTLE_ENDIAN,
CsInsn,
)
from capstone.mips import *
import spimdisasm
import rabbitizer
from segtypes.segment import Segment
from util.compiler import SN64
from util.symbols import Instruction, Symbol
from util import log
from util.symbols import Symbol
from util import symbols
# abstract class for c, asm, data, etc
class CommonSegCodeSubsegment(Segment):
double_mnemonics = ["ldc1", "sdc1"]
word_mnemonics = ["addiu", "sw", "lw", "jtbl"]
float_mnemonics = ["lwc1", "swc1"]
short_mnemonics = ["addiu", "lh", "sh", "lhu"]
byte_mnemonics = ["lb", "sb", "lbu"]
reg_numbers = {
"$zero": "$0",
"$at": "$1",
"$v0": "$2",
"$v1": "$3",
"$a0": "$4",
"$a1": "$5",
"$a2": "$6",
"$a3": "$7",
"$t0": "$8",
"$t1": "$9",
"$t2": "$10",
"$t3": "$11",
"$t4": "$12",
"$t5": "$13",
"$t6": "$14",
"$t7": "$15",
"$s0": "$16",
"$s1": "$17",
"$s2": "$18",
"$s3": "$19",
"$s4": "$20",
"$s5": "$21",
"$s6": "$22",
"$s7": "$23",
"$t8": "$24",
"$t9": "$25",
"$k0": "$26",
"$k1": "$27",
"$gp": "$28",
"$sp": "$sp",
"$fp": "$30",
"$ra": "$31",
}
if options.get_endianess() == "big":
capstone_mode = CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN
else:
capstone_mode = CS_MODE_MIPS32 | CS_MODE_LITTLE_ENDIAN
md = Cs(CS_ARCH_MIPS, capstone_mode)
md.detail = False
md.skipdata = True
double_mnemonics = [
rabbitizer.InstrId.cpu_ldc1,
rabbitizer.InstrId.cpu_sdc1,
]
word_mnemonics = [
rabbitizer.InstrId.cpu_addiu,
rabbitizer.InstrId.cpu_sw,
rabbitizer.InstrId.cpu_lw,
]
float_mnemonics = [
rabbitizer.InstrId.cpu_lwc1,
rabbitizer.InstrId.cpu_swc1,
]
short_mnemonics = [
rabbitizer.InstrId.cpu_addiu,
rabbitizer.InstrId.cpu_lh,
rabbitizer.InstrId.cpu_sh,
rabbitizer.InstrId.cpu_lhu,
]
byte_mnemonics = [
rabbitizer.InstrId.cpu_lb,
rabbitizer.InstrId.cpu_sb,
rabbitizer.InstrId.cpu_lbu,
]
@property
def needs_symbols(self) -> bool:
@ -80,545 +42,148 @@ class CommonSegCodeSubsegment(Segment):
def get_linker_section(self) -> str:
return ".text"
@staticmethod
def is_nops(insns: List[CsInsn]) -> bool:
for insn in insns:
if insn.mnemonic != "nop":
return False
return True
@staticmethod
def is_branch_insn(mnemonic):
return (
mnemonic.startswith("b")
and not mnemonic.startswith("binsl")
and not mnemonic == "break"
) or mnemonic == "j"
@staticmethod
def replace_reg_names(op_str):
for regname, regnum in CommonSegCodeSubsegment.reg_numbers.items():
op_str = op_str.replace(regname, regnum)
return op_str
def scan_code(self, rom_bytes, is_asm=False):
insns: List[CsInsn] = [
insn
for insn in CommonSegCodeSubsegment.md.disasm(
rom_bytes[self.rom_start : self.rom_end], self.vram_start
)
]
self.funcs: typing.OrderedDict[int, Symbol] = self.process_insns(
insns, self.rom_start, is_asm=is_asm
self.text_section = spimdisasm.mips.sections.SectionText(
symbols.spim_context,
self.rom_start,
self.rom_end,
self.vram_start,
self.name,
rom_bytes,
self.get_most_parent().rom_start,
self.get_exclusive_ram_id(),
)
# TODO: set these in creation
for func in self.funcs.values():
func.define = True
func.local_only = True
func.size = len(func.insns) * 4
for symbol_list in self.seg_symbols.values():
symbols.add_symbol_to_spim_section(self.text_section, symbol_list[0])
self.determine_symbols()
for sym in symbols.all_symbols:
if sym.user_declared:
symbols.add_symbol_to_spim_section(self.text_section, sym)
def split_code(self, rom_bytes):
self.text_section.isHandwritten = is_asm
self.text_section.analyze()
self.text_section.setCommentOffset(self.rom_start)
for func in self.text_section.symbolList:
assert isinstance(func, spimdisasm.mips.symbols.SymbolFunction)
self.process_insns(func)
# Process jumptable labels and pass them to spimdisasm
self.gather_jumptable_labels(rom_bytes)
return self.add_labels()
for jtbl_label_vram in self.parent.jtbl_glabels_to_add:
sym = self.create_symbol(
jtbl_label_vram, True, type="jtbl_label", define=True
)
sym.type = "jtbl_label"
symbols.add_symbol_to_spim_section(self.text_section, sym)
def process_insns(
self, insns: List[CsInsn], rom_addr, is_asm=False
) -> typing.OrderedDict[int, Symbol]:
self,
func_spim: spimdisasm.mips.symbols.SymbolFunction,
):
assert isinstance(self.parent, CommonSegCode)
assert func_spim.vram is not None
assert func_spim.vramEnd is not None
self.parent: CommonSegCode = self.parent
ret: typing.OrderedDict[int, Symbol] = OrderedDict()
symbols.create_symbol_from_spim_symbol(
self.get_most_parent(), func_spim.contextSym
)
end_func = False
start_new_func = True
labels = []
big_endian = options.get_endianess() == "big"
# Collect labels
for insn in insns:
if self.is_branch_insn(insn.mnemonic):
op_str_split = insn.op_str.split(" ")
branch_target = op_str_split[-1]
branch_addr = int(branch_target, 0)
labels.append((insn.address, branch_addr))
# Gather symbols found by spimdisasm and create those symbols in splat's side
for referenced_vram in func_spim.instrAnalyzer.referencedVrams:
context_sym = self.text_section.getSymbol(
referenced_vram, tryPlusOffset=False
)
if context_sym is not None:
if context_sym.type == spimdisasm.common.SymbolSpecialType.jumptable:
self.parent.jumptables[referenced_vram] = (
func_spim.vram,
func_spim.vramEnd,
)
symbols.create_symbol_from_spim_symbol(
self.get_most_parent(), context_sym
)
# Main loop
for i, insn in enumerate(insns):
mnemonic = insn.mnemonic
op_str = insn.op_str
for i, insn in enumerate(func_spim.instructions):
instr_offset = i * 4
# If this is non-zero, disasm size insns
hard_size = 0
# update pointer accesses from this function
if instr_offset in func_spim.instrAnalyzer.symbolInstrOffset:
sym_address = func_spim.instrAnalyzer.symbolInstrOffset[instr_offset]
if start_new_func:
func: Symbol = self.parent.create_symbol(insn.address, type="func")
start_new_func = False
if func.size > 4:
hard_size = func.size / 4
if options.get_compiler() == SN64:
op_str = self.replace_reg_names(op_str)
if mnemonic == "move":
# Let's get the actual instruction out
idx = 3 if big_endian else 0
opcode = insn.bytes[idx] & 0b00111111
if options.get_compiler() == SN64:
op_str += ", $0"
else:
op_str += ", $zero"
if opcode == 37:
mnemonic = "or"
elif opcode == 45:
mnemonic = "daddu"
elif opcode == 33:
mnemonic = "addu"
else:
print("INVALID INSTRUCTION " + str(insn), opcode)
elif mnemonic == "jal":
jal_addr = int(op_str, 0)
jump_func = self.parent.create_symbol(
jal_addr, type="func", reference=True
context_sym = self.text_section.getSymbol(
sym_address, tryPlusOffset=False
)
op_str = jump_func.name
elif self.is_branch_insn(insn.mnemonic):
op_str_split = op_str.split(" ")
branch_target = op_str_split[-1]
branch_target_int = int(branch_target, 0)
if context_sym is not None:
sym = symbols.create_symbol_from_spim_symbol(
self.get_most_parent(), context_sym
)
label_sym = self.parent.get_symbol(
branch_target_int, type="label", reference=True, local_only=True
)
if label_sym:
label_name = label_sym.name
else:
self.parent.labels_to_add.add(branch_target_int)
label_name = f".L{branch_target[2:].upper()}"
op_str = " ".join(op_str_split[:-1] + [label_name])
elif mnemonic in ["mtc0", "mfc0", "mtc2", "mfc2"]:
idx = 2 if big_endian else 1
rd = (insn.bytes[idx] & 0xF8) >> 3
op_str = op_str.split(" ")[0] + " $" + str(rd)
elif (
mnemonic == "break"
and op_str in ["6", "7"]
and options.get_compiler() == SN64
and not is_asm
):
# SN64's assembler expands div to have break if dividing by zero
# However, the break it generates is different than the one it generates with `break N`
# So we replace break instrutions for SN64 with the exact word that the assembler generates when expanding div
if op_str == "6":
mnemonic = ".word 0x0006000D"
op_str = ""
elif op_str == "7":
mnemonic = ".word 0x0007000D"
op_str = ""
elif (
mnemonic in ["div", "divu"]
and options.get_compiler() == SN64
and not is_asm
):
# SN64's assembler also doesn't like assembling `div $0, a, b` with .set noat active
# Removing the $0 fixes this issue
if op_str.startswith("$0, "):
op_str = op_str[4:]
func.insns.append(Instruction(insn, mnemonic, op_str, rom_addr))
rom_addr += 4
size_remaining = hard_size - len(func.insns) if hard_size > 0 else 0
if mnemonic == "jr":
# Record potential jtbl jumps
if op_str not in ["$ra", "$31"]:
self.parent.jtbl_jumps[insn.address] = op_str
keep_going = False
for label in labels:
if (label[0] > insn.address and label[1] <= insn.address) or (
label[0] <= insn.address and label[1] > insn.address
if any(
insn.uniqueId in mnemonics
for mnemonics in (
self.double_mnemonics,
self.word_mnemonics,
self.float_mnemonics,
self.short_mnemonics,
self.byte_mnemonics,
)
):
keep_going = True
break
if not keep_going and not size_remaining:
end_func = True
continue
self.update_access_mnemonic(sym, insn)
# Stop here if a size was specified and we have disassembled up to the size
if hard_size > 0 and size_remaining == 0:
end_func = True
if self.parent:
self.parent.check_rodata_sym(func_spim.vram, sym)
if i < len(insns) - 1 and self.parent.get_symbol(
insns[i + 1].address, local_only=True, type="func", dead=False
):
end_func = True
if end_func:
if (
self.is_nops(insns[i:])
or i < len(insns) - 1
and insns[i + 1].mnemonic != "nop"
):
end_func = False
start_new_func = True
ret[func.vram_start] = func
# Add the last function (or append nops to the previous one)
if not self.is_nops([insn.instruction for insn in func.insns]):
ret[func.vram_start] = func
else:
next(reversed(ret.values())).insns.extend(func.insns)
return ret
def update_access_mnemonic(self, sym, mnemonic):
def update_access_mnemonic(self, sym: Symbol, insn: rabbitizer.Instruction):
if not sym.access_mnemonic:
sym.access_mnemonic = mnemonic
elif sym.access_mnemonic == "addiu":
sym.access_mnemonic = mnemonic
sym.access_mnemonic = insn.uniqueId
elif sym.access_mnemonic in self.double_mnemonics:
return
elif (
sym.access_mnemonic in self.float_mnemonics
and mnemonic in self.double_mnemonics
and insn.uniqueId in self.double_mnemonics
):
sym.access_mnemonic = mnemonic
sym.access_mnemonic = insn.uniqueId
elif sym.access_mnemonic == rabbitizer.InstrId.cpu_addiu:
sym.access_mnemonic = insn.uniqueId
elif sym.access_mnemonic in self.short_mnemonics:
return
elif sym.access_mnemonic in self.byte_mnemonics:
return
else:
sym.access_mnemonic = mnemonic
sym.access_mnemonic = insn.uniqueId
# Determine symbols
def determine_symbols(self):
hi_lo_max_distance = options.hi_lo_max_distance()
def print_file_boundaries(self):
if not options.find_file_boundaries():
return
for func_addr in self.funcs:
func = self.funcs[func_addr]
func_end_addr = func.insns[-1].instruction.address + 4
for in_file_offset in self.text_section.fileBoundaries:
if (in_file_offset % 16) != 0:
continue
possible_jtbl_jumps = [
(k, v)
for k, v in self.parent.jtbl_jumps.items()
if k >= func_addr and k < func_end_addr
]
possible_jtbl_jumps.sort(key=lambda x: x[0])
if not self.parent.reported_file_split:
self.parent.reported_file_split = True
for i in range(len(func.insns)):
hi_insn: CsInsn = func.insns[i].instruction
# Look up for the last function in this boundary
func_addr = 0
for func in self.text_section.symbolList:
funcOffset = func.inFileOffset - self.text_section.inFileOffset
if in_file_offset == funcOffset:
break
func_addr = func.vram
# Ensure the first item in the list is always ahead of where we're looking
while (
len(possible_jtbl_jumps) > 0
and possible_jtbl_jumps[0][0] < hi_insn.address
):
del possible_jtbl_jumps[0]
# Find gp relative reads and writes e.g lw $a1, 0x670($gp)
if hi_insn.op_str.endswith("($gp)"):
gp_base = options.get_gp()
if gp_base is None:
log.error(
"gp_value not set in yaml, can't calculate %gp_rel reloc value for "
+ hi_insn.op_str
)
op_split = hi_insn.op_str.split(", ")
gp_offset = op_split[1][:-5] # extract the 0x670 part
if len(gp_offset) == 0:
gp_offset = 0
else:
gp_offset = int(gp_offset, 16)
symbol_addr = gp_base + gp_offset
sym = self.parent.create_symbol(
symbol_addr, offsets=True, reference=True
)
offset = symbol_addr - sym.vram_start
offset_str = f"+0x{offset:X}"
if self.parent:
self.parent.check_rodata_sym(func_addr, sym)
self.update_access_mnemonic(sym, hi_insn.mnemonic)
func.insns[i].is_gp = True
func.insns[i].hi_lo_sym = sym
func.insns[i].sym_offset_str = offset_str
# All hi/lo pairs start with a lui
elif hi_insn.mnemonic == "lui":
op_split = hi_insn.op_str.split(", ")
hi_reg = op_split[0]
if not op_split[1].startswith("0x"):
continue
lui_val = int(op_split[1], 0)
# Assumes all luis are going to load from 0x80000000 or higher (maybe false)
if lui_val >= 0x8000:
# Iterate over the next few instructions to see if we can find a matching lo
for j in range(
i + 1, min(i + hi_lo_max_distance, len(func.insns))
):
lo_insn = func.insns[j].instruction
s_op_split = lo_insn.op_str.split(", ")
if lo_insn.mnemonic == "lui" and hi_reg == s_op_split[0]:
break
if lo_insn.mnemonic in ["addiu", "ori"]:
lo_reg = s_op_split[-2]
else:
lo_reg = s_op_split[-1][
s_op_split[-1].rfind("(") + 1 : -1
]
if hi_reg == lo_reg:
if lo_insn.mnemonic not in [
"addiu",
"lw",
"sw",
"lh",
"sh",
"lhu",
"lb",
"sb",
"lbu",
"lwc1",
"swc1",
"ldc1",
"sdc1",
]:
break
# Match!
reg_ext = ""
# I forgot what this is doing
junk_search = re.search(r"[\(]", s_op_split[-1])
if junk_search is not None:
if junk_search.start() == 0:
break
s_str = s_op_split[-1][: junk_search.start()]
reg_ext = s_op_split[-1][junk_search.start() :]
else:
s_str = s_op_split[-1]
if options.get_compiler() == SN64:
reg_ext = CommonSegCodeSubsegment.replace_reg_names(
reg_ext
)
symbol_addr = (lui_val * 0x10000) + int(s_str, 0)
sym: Optional[Symbol] = None
offset_str = ""
# If the symbol is likely in the rodata section
if (
not self.parent.text_follows_rodata
and symbol_addr > func_addr
) or (
self.parent.text_follows_rodata
and symbol_addr < func_addr
):
# Sanity check that the symbol is within this segment's vram
if (
self.parent.vram_end
and symbol_addr < self.parent.vram_end
):
# If we've seen possible jumps to a jumptable and this symbol isn't too close to the end of the function
if (
len(possible_jtbl_jumps) > 0
and func_end_addr - lo_insn.address >= 0x30
):
for jump in possible_jtbl_jumps:
if jump[1] == s_op_split[0]:
dist_to_jump = (
possible_jtbl_jumps[0][0]
- lo_insn.address
)
if dist_to_jump <= 16:
sym = self.parent.create_symbol(
symbol_addr,
reference=True,
type="jtbl",
local_only=True,
)
self.parent.jumptables[
symbol_addr
] = (func_addr, func_end_addr)
break
if not sym:
sym = self.parent.create_symbol(
symbol_addr, offsets=True, reference=True
)
offset = symbol_addr - sym.vram_start
if offset != 0:
offset_str = f"+0x{offset:X}"
if self.parent:
self.parent.check_rodata_sym(func_addr, sym)
self.update_access_mnemonic(sym, lo_insn.mnemonic)
func.insns[i].is_hi = True
func.insns[i].hi_lo_sym = sym
func.insns[i].sym_offset_str = offset_str
func.insns[j].is_lo = True
func.insns[j].hi_lo_sym = sym
func.insns[j].sym_offset_str = offset_str
func.insns[j].hi_lo_reg = reg_ext
break
def add_labels(self):
ret = {}
function_macro = options.get_asm_function_macro()
data_macro = options.get_asm_data_macro()
for func_addr in self.funcs:
func_text = []
func = self.funcs[func_addr]
# Add function label
func_text.append(f"{function_macro} {func.name}")
if options.get_compiler() == SN64:
func_text.append(f".ent {func.name}")
func_text.append(f"{func.name}:")
indent_next = False
mnemonic_ljust = options.mnemonic_ljust()
rom_addr_padding = options.rom_address_padding()
for insn in func.insns:
insn_addr = insn.instruction.address
# Add a label if we need one
if insn_addr in self.parent.jtbl_glabels_to_add:
func_text.append(f"{data_macro} L{insn_addr:X}_{insn.rom_addr:X}")
elif insn_addr in self.parent.labels_to_add:
self.parent.labels_to_add.remove(insn_addr)
func_text.append(".L{:X}:".format(insn_addr))
if rom_addr_padding:
rom_str = "{0:0{1}X}".format(insn.rom_addr, rom_addr_padding)
else:
rom_str = "{:X}".format(insn.rom_addr)
if options.get_compiler() == SN64:
asm_comment = ""
else:
asm_comment = "/* {} {:X} {} */".format(
rom_str, insn_addr, insn.instruction.bytes.hex().upper()
)
if insn.is_hi:
assert insn.hi_lo_sym
op_str = ", ".join(
insn.op_str.split(", ")[:-1]
+ [f"%hi({insn.hi_lo_sym.name}{insn.sym_offset_str})"]
)
elif insn.is_lo:
assert insn.hi_lo_sym
op_str = ", ".join(
insn.op_str.split(", ")[:-1]
+ [
f"%lo({insn.hi_lo_sym.name}{insn.sym_offset_str}){insn.hi_lo_reg}"
]
)
elif insn.is_gp:
op_str = ", ".join(
insn.op_str.split(", ")[:-1]
+ [f"%gp_rel({insn.hi_lo_sym.name}{insn.sym_offset_str})($gp)"]
)
else:
op_str = insn.op_str
if self.is_branch_insn(insn.instruction.mnemonic):
branch_addr = int(insn.instruction.op_str.split(",")[-1].strip(), 0)
if branch_addr in self.parent.jtbl_glabels_to_add:
label_str = f"L{branch_addr:X}_{self.ram_to_rom(branch_addr):X}"
op_str = ", ".join(insn.op_str.split(", ")[:-1] + [label_str])
insn_text = insn.mnemonic
if indent_next:
indent_next = False
insn_text = " " + insn_text
asm_insn_text = " {}{}".format(
insn_text.ljust(mnemonic_ljust), op_str
).rstrip()
func_text.append(asm_comment + asm_insn_text)
if (
insn.instruction.mnemonic != "branch"
and insn.instruction.mnemonic.startswith("b")
or insn.instruction.mnemonic.startswith("j")
):
indent_next = True
end_label = options.get_asm_end_label()
if end_label:
func_text.append(f"{end_label} {func.name}")
ret[func_addr] = (func_text, func.rom)
if options.find_file_boundaries():
# If this is not the last function in the file
if func_addr != list(self.funcs.keys())[-1]:
# Find where the function returns
jr_pos: Optional[int] = None
for i, insn in enumerate(reversed(func.insns)):
if (
insn.instruction.mnemonic == "jr"
and insn.instruction.op_str in ["$ra", "$31"]
):
jr_pos = i
break
# If there is more than 1 nop after the return
if (
jr_pos is not None
and jr_pos > 1
and self.is_nops(
[insn.instruction for insn in func.insns[-jr_pos + 1 :]]
)
):
new_file_addr = func.insns[-1].rom_addr + 4
if (new_file_addr % 16) == 0:
if not self.parent.reported_file_split:
self.parent.reported_file_split = True
print(
f"Segment {self.name}, function at vram {func_addr:X} ends with extra nops, indicating a likely file split."
)
print(
"File split suggestions for this segment will follow in config yaml format:"
)
print(f" - [0x{new_file_addr:X}, asm]")
return ret
print(
f"Segment {self.name}, function at vram {func_addr:X} ends with extra nops, indicating a likely file split."
)
print(
"File split suggestions for this segment will follow in config yaml format:"
)
print(f" - [0x{self.rom_start+in_file_offset:X}, asm]")
def gather_jumptable_labels(self, rom_bytes):
# TODO: use the seg_symbols for this

View File

@ -3,6 +3,7 @@ from segtypes.common.codesubsegment import CommonSegCodeSubsegment
from segtypes.common.group import CommonSegGroup
from pathlib import Path
from typing import List, Optional
import rabbitizer
from util.symbols import Symbol
from util import floats, options
@ -80,13 +81,15 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
new_sym_ram_start = self.get_most_parent().rom_to_ram(
new_sym_rom_start
)
sym.size = new_sym_rom_start - sym.rom
assert sym.rom is not None
assert new_sym_ram_start is not None
sym.given_size = new_sym_rom_start - sym.rom
# It turns out this isn't a valid jump table, so create a new symbol where it breaks
syms.insert(
i + 1,
self.get_most_parent().create_symbol(
new_sym_ram_start, define=True, local_only=True
self.create_symbol(
new_sym_ram_start, True, define=True, local_only=True
),
)
return False
@ -102,12 +105,13 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
endian = options.get_endianess()
# Find inter-data symbols
assert isinstance(self.rom_start, int) and isinstance(self.rom_end, int)
for i in range(self.rom_start, self.rom_end, 4):
bits = int.from_bytes(rom_bytes[i : i + 4], endian)
if self.contains_vram(bits):
symset.add(
self.get_most_parent().create_symbol(
bits, define=True, local_only=True
self.create_symbol(
bits, in_segment=True, define=True, local_only=True
)
)
@ -123,12 +127,13 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
if len(ret) == 0 or ret[0].vram_start != self.vram_start:
ret.insert(
0,
self.get_most_parent().create_symbol(
self.vram_start, define=True, local_only=True
self.create_symbol(
self.vram_start, in_segment=True, define=True, local_only=True
),
)
# Make a dummy symbol here that marks the end of the previous symbol's disasm range
assert self.vram_end is not None
ret.append(Symbol(self.vram_end))
while True:
@ -231,6 +236,10 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
if not jtbl_func:
return False
# A label of a jump table shouldn't point to the start of the function
if word == jtbl_func.vram_start:
return False
for i in range(4, len(bytes), 4):
word = int.from_bytes(bytes[i : i + 4], options.get_endianess())
@ -240,6 +249,10 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
if i < min_jtbl_len or any(b != 0 for b in bytes[i:]):
return False
# A label of a jump table shouldn't point to the start of the function
if word == jtbl_func.vram_start:
return False
# Mark this symbol as a jump table and record the jump table for later
sym.type = "jtbl"
most_parent.jumptables[sym.vram_start] = (
@ -287,14 +300,13 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
if bits == 0:
byte_str = "0"
else:
rom_addr = self.get_most_parent().ram_to_rom(bits)
if rom_addr:
byte_str = f"L{bits:X}_{rom_addr:X}"
sym = self.get_symbol(bits, True)
if sym is not None:
byte_str = sym.name
else:
byte_str = f"0x{bits:X}"
elif slen == 4 and bits >= 0x80000000:
sym = self.get_most_parent().get_symbol(bits, reference=True)
sym = self.get_symbol(bits, reference=True)
if sym:
byte_str = sym.name
else:
@ -336,12 +348,13 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
for i in range(len(syms) - 1):
mnemonic = syms[i].access_mnemonic
sym = self.get_most_parent().create_symbol(
syms[i].vram_start, define=True, local_only=True
sym = self.create_symbol(
syms[i].vram_start, in_segment=True, define=True, local_only=True
)
dis_start = self.get_most_parent().ram_to_rom(syms[i].vram_start)
dis_end = self.get_most_parent().ram_to_rom(syms[i + 1].vram_start)
assert dis_start is not None and dis_end is not None
sym_len = dis_end - dis_start
if self.type == "bss":
@ -350,7 +363,10 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
sym_bytes = rom_bytes[dis_start:dis_end]
# Checking if the mnemonic is addiu may be too picky - we'll see
if self.is_valid_ascii(sym_bytes) and mnemonic == "addiu":
if (
self.is_valid_ascii(sym_bytes)
and mnemonic == rabbitizer.InstrId.cpu_addiu
):
stype = "ascii"
elif sym.type == "jtbl":
stype = "jtbl"
@ -396,7 +412,7 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
# Hint to the user that we are now in the .rodata section and no longer in the .data section (assuming rodata follows data)
if (
not rodata_encountered
and mnemonic == "jtbl"
and stype == "jtbl"
and self.get_most_parent().rodata_follows_data
):
rodata_encountered = True

View File

@ -1,14 +1,8 @@
from collections import OrderedDict
from typing import List, Dict, Optional
import typing
from typing import List, Optional
from segtypes.common.linker_section import dotless_type
from util.range import Range
from util import log, options
from segtypes.common.segment import CommonSegment
from segtypes.segment import RomAddr, Segment
from util.symbols import Symbol
CODE_TYPES = ["c", "asm", "hasm"]
from util import log
class CommonSegGroup(CommonSegment):
@ -21,8 +15,10 @@ class CommonSegGroup(CommonSegment):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
@ -34,85 +30,15 @@ class CommonSegGroup(CommonSegment):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.rodata_syms: Dict[int, List[Symbol]] = {}
# TODO: move this to CommonSegCode
self.section_boundaries = OrderedDict(
(s_name, Range()) for s_name in options.get_section_order()
)
self.subsegments = self.parse_subsegments(yaml)
@property
def needs_symbols(self) -> bool:
for seg in self.subsegments:
if seg.needs_symbols:
return True
return False
def handle_alls(self, segs: List[Segment], base_segs) -> bool:
for i, elem in enumerate(segs):
if elem.type.startswith("all_"):
alls = []
rep_type = f"{elem.type[4:]}"
replace_class = Segment.get_class_for_type(rep_type)
for base in base_segs.items():
if isinstance(elem.rom_start, int):
# Shoddy rom to ram
vram_start = elem.rom_start - self.rom_start + self.vram_start
else:
vram_start = "auto"
rep = replace_class(
elem.rom_start,
elem.rom_end,
rep_type,
base[0],
vram_start,
False,
self.given_subalign,
self.given_is_overlay,
self.given_dir,
[],
{},
)
rep.sibling = base[1]
rep.parent = self
alls.append(rep)
# Insert alls into segs at i
del segs[i]
segs[i:i] = alls
return True
return False
def find_inserts(
self, found_sections: typing.OrderedDict[str, Range]
) -> "OrderedDict[str, int]":
inserts = OrderedDict()
section_order = self.section_order
section_order.remove(".text")
for i, section in enumerate(section_order):
if not found_sections[section].has_start():
search_done = False
for j in range(i - 1, -1, -1):
if found_sections[section_order[j]].has_end():
inserts[section] = found_sections[section_order[j]].end
search_done = True
break
if not search_done:
inserts[section] = -1
pass
return inserts
self.subsegments: List[Segment] = self.parse_subsegments(yaml)
def get_next_seg_start(self, i, subsegment_yamls):
return (
@ -121,87 +47,25 @@ class CommonSegGroup(CommonSegment):
else Segment.parse_segment_start(subsegment_yamls[i + 1])
)
def parse_subsegments(self, segment_yaml) -> List[Segment]:
base_segments: OrderedDict[str, Segment] = OrderedDict()
ret = []
def parse_subsegments(self, yaml) -> List[Segment]:
ret: List[Segment] = []
if not yaml or "subsegments" not in yaml:
return ret
prev_start: RomAddr = -1
inserts: OrderedDict[
str, int
] = (
OrderedDict()
) # Used to manually add "all_" types for sections not otherwise defined in the yaml
found_sections = OrderedDict(
(s_name, Range()) for s_name in self.section_boundaries
) # Stores yaml index where a section was first found
if "subsegments" not in segment_yaml:
return []
# Mark any manually added dot types
if options.auto_all_sections():
cur_section = None
for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
# rompos marker
if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
if cur_section is not None:
# End the current section
found_sections[cur_section].end = i
cur_section = None
continue
typ = Segment.parse_segment_type(subsection_yaml)
if typ.startswith("all_"):
typ = typ[4:]
if not typ.startswith("."):
typ = f".{typ}"
if typ in found_sections:
if cur_section is None:
# Starting point
found_sections[typ].start = i
cur_section = typ
else:
if cur_section != typ:
# We're changing sections
if found_sections[cur_section].has_end():
log.error(
f"Section {cur_section} end encountered but was already ended earlier!"
)
if found_sections[typ].has_start():
log.error(
f"Section {typ} start encounted but has already started earlier!"
)
# End the current section
found_sections[cur_section].end = i
# Start the next section
found_sections[typ].start = i
cur_section = typ
if cur_section is not None:
found_sections[cur_section].end = len(segment_yaml["subsegments"])
inserts = self.find_inserts(found_sections)
for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
# rompos marker
for i, subsection_yaml in enumerate(yaml["subsegments"]):
# End of previous segment
if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
continue
typ = Segment.parse_segment_type(subsection_yaml)
start = Segment.parse_segment_start(subsection_yaml)
# Add dummy segments to be expanded later
if typ.startswith("all_"):
ret.append(Segment(start, "auto", typ, "", "auto"))
continue
segment_class = Segment.get_class_for_type(typ)
end = self.get_next_seg_start(i, segment_yaml["subsegments"])
end = self.get_next_seg_start(i, yaml["subsegments"])
if (
isinstance(start, int)
@ -220,72 +84,26 @@ class CommonSegGroup(CommonSegment):
segment: Segment = Segment.from_yaml(
segment_class, subsection_yaml, start, end, vram
)
segment.sibling = base_segments.get(segment.name, None)
segment.parent = self
for i, section in enumerate(self.section_order):
if not self.section_boundaries[section].has_start() and dotless_type(
section
) == dotless_type(segment.type):
if i > 0:
prev_section = self.section_order[i - 1]
self.section_boundaries[prev_section].end = segment.vram_start
self.section_boundaries[section].start = segment.vram_start
ret.append(segment)
# todo change
if typ in CODE_TYPES:
base_segments[segment.name] = segment
prev_start = start
# Add the automatic all_ sections
orig_len = len(ret)
for section in reversed(inserts):
idx = inserts[section]
if idx == -1:
idx = orig_len
# bss hack TODO maybe rethink
if section == "bss" and self.vram_start is not None:
rom_start = self.rom_end
vram_start = self.vram_start + self.rom_end - self.rom_start
else:
rom_start = "auto"
vram_start = "auto"
ret.insert(
idx, (Segment(rom_start, "auto", "all_" + section, "", vram_start))
)
check = True
while check:
check = self.handle_alls(ret, base_segments)
# TODO why is this necessary?
if (
self.section_boundaries[".rodata"].has_start()
and not self.section_boundaries[".rodata"].has_end()
):
assert self.vram_end is not None
self.section_boundaries[".rodata"].end = self.vram_end
return ret
@property
def needs_symbols(self) -> bool:
for seg in self.subsegments:
if seg.needs_symbols:
return True
return False
def get_linker_entries(self):
return [entry for sub in self.subsegments for entry in sub.get_linker_entries()]
def scan(self, rom_bytes):
# Always scan code first
for sub in self.subsegments:
if sub.type in CODE_TYPES and sub.should_scan():
sub.scan(rom_bytes)
# Scan everyone else
for sub in self.subsegments:
if sub.type not in CODE_TYPES and sub.should_scan():
if sub.should_scan():
sub.scan(rom_bytes)
def split(self, rom_bytes):

View File

@ -0,0 +1,16 @@
from segtypes.common.asm import CommonSegAsm
class CommonSegHasm(CommonSegAsm):
def split(self, rom_bytes: bytes):
if not self.rom_start == self.rom_end:
out_path = self.out_path()
if out_path and not out_path.exists():
out_path.parent.mkdir(parents=True, exist_ok=True)
self.print_file_boundaries()
with open(out_path, "w", newline="\n") as f:
for line in self.get_file_header():
f.write(line + "\n")
f.write(self.text_section.disassemble())

View File

@ -14,8 +14,10 @@ class CommonSegLib(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
@ -27,11 +29,14 @@ class CommonSegLib(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
if isinstance(yaml, dict):
log.error("Error: 'dict' not currently supported for 'lib' segment")
return

View File

@ -1,6 +1,9 @@
from typing import Union, List
from pathlib import Path
from segtypes.common.data import CommonSegData
from segtypes.common.linker_section import LinkerSection, dotless_type
from segtypes.n64.img import N64SegImg
from segtypes.n64.palette import N64SegPalette
from util import options
from segtypes.segment import Segment
import os
@ -57,10 +60,14 @@ def to_cname(symbol: str) -> str:
def get_segment_cname(segment: Segment) -> str:
name = segment.name
if segment.parent:
return to_cname(segment.parent.name + "_" + segment.name)
else:
return to_cname(segment.name)
name = segment.parent.name + "_" + name
if isinstance(segment, N64SegPalette):
name += "_pal"
return to_cname(name)
class LinkerEntry:
@ -163,6 +170,15 @@ class LinkerWriter:
)
self._write_symbol(path_cname, ".")
# Write out manual entries for images inside .data segments
seg = entry.segment
if isinstance(seg, CommonSegData):
for subseg in seg.subsegments:
if isinstance(subseg, N64SegImg):
self._write_symbol(
get_segment_cname(subseg), f"0x{subseg.rom_start:X}"
)
self._writeln(f"{entry.object_path}({cur_section});")
for section in section_labels:

View File

@ -19,8 +19,10 @@ class N64SegCi8(N64SegRgba16):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
@ -32,10 +34,12 @@ class N64SegCi8(N64SegRgba16):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.palette: "Optional[Palette]" = None
@ -52,7 +56,6 @@ class N64SegCi8(N64SegRgba16):
log.error(
f"no palette sibling segment exists\n(hint: add a segment with type 'palette' and name '{self.name}')"
)
return
w = png.Writer(
self.width, self.height, palette=self.palette.parse_palette(rom_bytes)

View File

@ -1,7 +0,0 @@
from segtypes.n64.c import N64SegC
from util import options
class N64SegCpp(N64SegC):
def out_path(self):
return options.get_src_path() / self.dir / f"{self.name}.cpp"

View File

@ -0,0 +1,214 @@
"""
N64 f3dex display list splitter
Dumps out Gfx[] as a .inc.c file.
"""
from pathlib import Path
from pygfxd import *
from util import log
from util.log import error
from util import options
from segtypes.common.codesubsegment import CommonSegCodeSubsegment
class N64SegGfx(CommonSegCodeSubsegment):
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.file_text = None
def get_linker_section(self) -> str:
return ".data"
def out_path(self) -> Path:
return options.get_asset_path() / self.dir / f"{self.name}.gfx.inc.c"
def scan(self, rom_bytes: bytes):
self.file_text = self.disassemble_data(rom_bytes)
def get_gfxd_target(self):
opt = options.get_gfx_ucode()
if opt == "f3d":
return gfxd_f3d # type: ignore
elif opt == "f3db":
return gfxd_f3db # type: ignore
elif opt == "f3dex":
return gfxd_f3dex # type: ignore
elif opt == "f3dexb":
return gfxd_f3dexb # type: ignore
elif opt == "f3dex2":
return gfxd_f3dex2 # type: ignore
else:
log.error(f"Unknown target {opt}")
def tlut_handler(self, addr, idx, count):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def timg_handler(self, addr, fmt, size, width, height, pal):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def cimg_handler(self, addr, fmt, size, width):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def zimg_handler(self, addr):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def dl_handler(self, addr):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def mtx_handler(self, addr):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def lookat_handler(self, addr, count):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def light_handler(self, addr, count):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def vtx_handler(self, addr, count):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def vp_handler(self, addr):
sym = self.create_symbol(
addr=addr, in_segment=True, type="data", reference=True
)
gfxd_printf(sym.name)
return 1
def macro_fn(self):
gfxd_puts(" ")
gfxd_macro_dflt()
gfxd_puts(",\n")
return 0
def disassemble_data(self, rom_bytes):
gfx_data = rom_bytes[self.rom_start : self.rom_end]
segment_length = len(gfx_data)
if (segment_length) % 8 != 0:
error(
f"Error: gfx segment {self.name} length ({segment_length}) is not a multiple of 8!"
)
out_str = options.get_generated_c_premble() + "\n\n"
sym = self.create_symbol(
addr=self.vram_start, in_segment=True, type="data", define=True
)
gfxd_input_buffer(gfx_data)
# TODO terrible guess at the size we'll need - improve this
outb = bytes([0] * segment_length * 100)
outbuf = gfxd_output_buffer(outb, len(outb))
gfxd_target(self.get_gfxd_target())
gfxd_endian(
GfxdEndian.big if options.get_endianess() == "big" else GfxdEndian.little, 4
)
# Callbacks
gfxd_macro_fn(self.macro_fn)
gfxd_tlut_callback(self.tlut_handler)
gfxd_timg_callback(self.timg_handler)
gfxd_cimg_callback(self.cimg_handler)
gfxd_zimg_callback(self.zimg_handler)
gfxd_dl_callback(self.dl_handler)
gfxd_mtx_callback(self.mtx_handler)
gfxd_lookat_callback(self.lookat_handler)
gfxd_light_callback(self.light_handler)
# gfxd_seg_callback ?
gfxd_vtx_callback(self.vtx_handler)
gfxd_vp_callback(self.vp_handler)
# gfxd_uctext_callback ?
# gfxd_ucdata_callback ?
# gfxd_dram_callback ?
gfxd_execute()
out_str += "Gfx " + sym.name + "[] = {\n"
out_str += gfxd_buffer_to_string(outbuf)
out_str += "};\n"
return out_str
def split(self, rom_bytes: bytes):
if self.file_text and self.out_path():
self.out_path().parent.mkdir(parents=True, exist_ok=True)
with open(self.out_path(), "w", newline="\n") as f:
f.write(self.file_text)
def should_scan(self) -> bool:
return (
options.mode_active("gfx")
and self.rom_start != "auto"
and self.rom_end != "auto"
)
def should_split(self) -> bool:
return self.extract and options.mode_active("gfx")

View File

@ -1,8 +1,25 @@
from segtypes.n64.asm import N64SegAsm
from segtypes.common.hasm import CommonSegHasm
from util import options
class N64SegHasm(N64SegAsm):
def split_write(self, out_path, out_lines):
if not out_path.exists():
with open(out_path, "w", newline="\n") as f:
f.write("\n".join(out_lines))
class N64SegHasm(CommonSegHasm):
@staticmethod
def get_file_header():
ret = []
ret.append('.include "macro.inc"')
ret.append("")
ret.append("# assembler directives")
ret.append(".set noat # allow manual use of $at")
ret.append(".set noreorder # don't insert nops after branches")
ret.append(".set gp=64 # allow use of 64-bit general purpose registers")
ret.append("")
preamble = options.get_generated_s_preamble()
if preamble:
ret.append(preamble)
ret.append("")
ret.append('.section .text, "ax"')
ret.append("")
return ret

View File

@ -15,8 +15,10 @@ class N64SegImg(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
@ -28,10 +30,12 @@ class N64SegImg(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
if isinstance(yaml, dict):

View File

@ -23,8 +23,10 @@ class N64SegPalette(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
@ -36,10 +38,12 @@ class N64SegPalette(N64Segment):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.raster: "Optional[Raster]" = None
@ -81,7 +85,6 @@ class N64SegPalette(N64Segment):
if self.raster is None:
# TODO: output with no raster
log.error(f"orphaned palette segment: {self.name} lacks ci4/ci8 sibling")
return
w = png.Writer(
self.raster.width, self.raster.height, palette=self.parse_palette(rom_bytes)

View File

@ -7,7 +7,6 @@ Originally written by Mark Street (https://github.com/mkst)
import re
import struct
from typing import Optional
from pathlib import Path
from util.log import error
@ -25,10 +24,12 @@ class N64SegVtx(CommonSegCodeSubsegment):
vram_start,
extract,
given_subalign,
given_is_overlay,
exclusive_ram_id,
given_dir,
args=[],
yaml={},
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
@ -38,10 +39,12 @@ class N64SegVtx(CommonSegCodeSubsegment):
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.file_text = None
@ -68,8 +71,10 @@ class N64SegVtx(CommonSegCodeSubsegment):
lines.append("")
vertex_count = segment_length // 16
cname = re.sub(r"[^0-9a-zA-Z_]", "_", self.name)
lines.append(f"Vtx {cname}[{vertex_count}] = {{")
sym = self.create_symbol(
addr=self.vram_start, in_segment=True, type="data", define=True
)
lines.append(f"Vtx {sym.name}[{vertex_count}] = {{")
for vtx in struct.iter_unpack(">hhhHhhBBBB", vertex_data):
x, y, z, flg, t, c, r, g, b, a = vtx

View File

@ -1,8 +0,0 @@
from segtypes.psx.asm import PsxSegAsm
class PsxSegHasm(PsxSegAsm):
def split_write(self, out_path, out_lines):
if not out_path.exists():
with open(out_path, "w", newline="\n") as f:
f.write("\n".join(out_lines))

View File

@ -1,7 +1,7 @@
import importlib
import importlib.util
from typing import Dict, TYPE_CHECKING, Type, Union, Optional, List
from typing import Any, Dict, TYPE_CHECKING, Type, Union, Optional, List
from pathlib import Path
from util import log
@ -41,7 +41,7 @@ class Segment:
require_unique_name = True
@staticmethod
def get_class_for_type(seg_type):
def get_class_for_type(seg_type) -> Type["Segment"]:
# so .data loads SegData, for example
if seg_type.startswith("."):
seg_type = seg_type[1:]
@ -126,17 +126,33 @@ class Segment:
else:
return str(cls.get_default_name(rom_start))
@staticmethod
def parse_segment_symbol_name_format(segment: Union[dict, list]) -> str:
if isinstance(segment, dict) and "symbol_name_format" in segment:
return str(segment["symbol_name_format"])
else:
return options.get_symbol_name_format()
@staticmethod
def parse_segment_symbol_name_format_no_rom(segment: Union[dict, list]) -> str:
if isinstance(segment, dict) and "symbol_name_format_no_rom" in segment:
return str(segment["symbol_name_format_no_rom"])
else:
return options.get_symbol_name_format_no_rom()
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract=True,
given_subalign=options.get_subalign(),
given_is_overlay: Optional[bool] = False,
rom_start: RomAddr,
rom_end: RomAddr,
type: str,
name: str,
vram_start: Any,
extract: bool = True,
given_subalign: int = options.get_subalign(),
exclusive_ram_id: Optional[str] = None,
given_dir: Path = Path(),
symbol_name_format: str = options.get_symbol_name_format(),
symbol_name_format_no_rom: str = options.get_symbol_name_format_no_rom(),
args=[],
yaml={},
):
@ -148,27 +164,22 @@ class Segment:
self.extract = extract
self.given_subalign = given_subalign
self.given_is_overlay = given_is_overlay
self.exclusive_ram_id = exclusive_ram_id
self.given_dir = given_dir
self.given_seg_symbols: Dict[
int, List[Symbol]
] = {} # Symbols known to be in this segment
self.given_ext_symbols: Dict[
int, List[Symbol]
] = (
{}
) # Symbols not in this segment but also not from other overlapping ram address ranges
self.given_section_order: List[str] = options.get_section_order()
self.given_symbol_name_format = symbol_name_format
self.given_symbol_name_format_no_rom = symbol_name_format_no_rom
self.parent: Optional[Segment] = None
self.sibling: Optional[Segment] = None
self.args: List[str] = args
self.yaml = yaml
if "skip" in self.args:
self.extract = False
if self.rom_start == "auto":
self.extract = False
@ -197,24 +208,30 @@ class Segment:
vram_start = vram if vram is not None else parse_segment_vram(yaml)
extract = bool(yaml.get("extract", True)) if isinstance(yaml, dict) else True
given_subalign = parse_segment_subalign(yaml)
given_is_overlay: Optional[bool] = (
yaml.get("overlay", False) if isinstance(yaml, dict) else False
exclusive_ram_id: Optional[str] = (
yaml.get("exclusive_ram_id") if isinstance(yaml, dict) else None
)
given_dir = Path(yaml.get("dir", "")) if isinstance(yaml, dict) else Path()
given_symbol_name_format = Segment.parse_segment_symbol_name_format(yaml)
given_symbol_name_format_no_rom = (
Segment.parse_segment_symbol_name_format_no_rom(yaml)
)
args: List[str] = [] if isinstance(yaml, dict) else yaml[3:]
ret = cls(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
given_is_overlay,
given_dir,
args,
yaml,
rom_start=rom_start,
rom_end=rom_end,
type=type,
name=name,
vram_start=vram_start,
extract=extract,
given_subalign=given_subalign,
exclusive_ram_id=exclusive_ram_id,
given_dir=given_dir,
symbol_name_format=given_symbol_name_format,
symbol_name_format_no_rom=given_symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
cls.given_section_order = parse_segment_section_order(yaml)
return ret
@ -230,6 +247,14 @@ class Segment:
else:
return self.given_dir
@property
def symbol_name_format(self) -> str:
return self.given_symbol_name_format
@property
def symbol_name_format_no_rom(self) -> str:
return self.given_symbol_name_format_no_rom
@property
def subalign(self) -> int:
if self.parent:
@ -237,13 +262,15 @@ class Segment:
else:
return self.given_subalign
@property
def is_overlay(self) -> bool:
def get_exclusive_ram_id(self) -> Optional[str]:
if self.parent:
return self.parent.is_overlay
if self.given_is_overlay is not None:
return self.given_is_overlay
return False
return self.parent.get_exclusive_ram_id()
return self.exclusive_ram_id
def add_symbol(self, symbol: Symbol):
if symbol.vram_start not in self.given_seg_symbols:
self.given_seg_symbols[symbol.vram_start] = []
self.given_seg_symbols[symbol.vram_start].append(symbol)
@property
def seg_symbols(self) -> Dict[int, List[Symbol]]:
@ -252,13 +279,6 @@ class Segment:
else:
return self.given_seg_symbols
@property
def ext_symbols(self) -> Dict[int, List[Symbol]]:
if self.parent:
return self.parent.ext_symbols
else:
return self.given_ext_symbols
@property
def size(self) -> Optional[int]:
if isinstance(self.rom_start, int) and isinstance(self.rom_end, int):
@ -285,14 +305,6 @@ class Segment:
self.section_order.index(".rodata") - self.section_order.index(".data") == 1
)
@property
def text_follows_rodata(self) -> bool:
if ".text" not in self.section_order or ".rodata" not in self.section_order:
return False
return (
self.section_order.index(".text") - self.section_order.index(".rodata") == 1
)
def contains_vram(self, vram: int) -> bool:
if self.vram_start is not None and self.vram_end is not None:
return vram >= self.vram_start and vram < self.vram_end
@ -395,43 +407,59 @@ class Segment:
def get_default_name(addr) -> str:
return f"{addr:X}"
def retrieve_symbol(self, d, k, t):
if k not in d:
@staticmethod
def visible_ram(seg1: "Segment", seg2: "Segment") -> bool:
if seg1.get_most_parent() == seg2.get_most_parent():
return True
if seg1.get_exclusive_ram_id() is None or seg2.get_exclusive_ram_id() is None:
return True
return seg1.get_exclusive_ram_id() != seg2.get_exclusive_ram_id()
def retrieve_symbol(
self, syms: Dict[int, List[Symbol]], addr: int
) -> Optional[Symbol]:
if addr not in syms:
return None
if t:
items = [s for s in d[k] if s.type == t or s.type == "unknown"]
else:
items = d[k]
items = syms[addr]
# Filter out symbols that are in different top-level segments with the same unique_ram_id
items = [
i
for i in items
if i.segment is None or Segment.visible_ram(self, i.segment)
]
if len(items) > 1:
pass # print(f"Trying to retrieve {k:X} from symbol dict but there are {len(items)} entries to pick from - picking the first")
# print(f"Trying to retrieve {addr:X} from symbol dict but there are {len(items)} entries to pick from - picking the first")
pass
if len(items) == 0:
return None
return items[0]
def get_symbol(
self,
addr,
type=None,
create=False,
define=False,
reference=False,
offsets=False,
local_only=False,
dead=True,
addr: int,
in_segment: bool = False,
type: Optional[str] = None,
create: bool = False,
define: bool = False,
reference: bool = False,
offsets: bool = False,
local_only: bool = False,
dead: bool = True,
) -> Optional[Symbol]:
ret = None
rom = None
ret: Optional[Symbol] = None
rom: Optional[int] = None
in_segment = self.contains_vram(addr)
most_parent = self.get_most_parent()
if in_segment:
# If the vram address is within this segment, we can calculate the symbol's rom address
rom = self.ram_to_rom(addr)
ret = self.retrieve_symbol(self.seg_symbols, addr, type)
rom = most_parent.ram_to_rom(addr)
ret = most_parent.retrieve_symbol(most_parent.seg_symbols, addr)
elif not local_only:
ret = self.retrieve_symbol(self.ext_symbols, addr, type)
ret = most_parent.retrieve_symbol(symbols.all_symbols_dict, addr)
# Search for symbol ranges
if not ret and offsets:
@ -444,39 +472,43 @@ class Segment:
# Create the symbol if it doesn't exist
if not ret and create:
ret = Symbol(addr, rom=rom, type=type)
symbols.all_symbols.append(ret)
symbols.add_symbol(ret)
if in_segment:
if self.is_overlay:
ret.in_overlay = True
if addr not in self.seg_symbols:
self.seg_symbols[addr] = []
self.seg_symbols[addr].append(ret)
elif not local_only:
if addr not in self.ext_symbols:
self.ext_symbols[addr] = []
self.ext_symbols[addr].append(ret)
ret.segment = most_parent
if addr not in most_parent.seg_symbols:
most_parent.seg_symbols[addr] = []
most_parent.seg_symbols[addr].append(ret)
if ret:
if define:
ret.defined = True
if reference:
ret.referenced = True
if ret.type is None:
ret.type = type
if ret.rom is None:
ret.rom = rom
if in_segment:
if ret.segment is None:
ret.segment = most_parent
return ret
def create_symbol(
self,
addr,
type=None,
define=False,
reference=False,
offsets=False,
local_only=False,
dead=True,
addr: int,
in_segment: bool,
type: Optional[str] = None,
define: bool = False,
reference: bool = False,
offsets: bool = False,
local_only: bool = False,
dead: bool = True,
) -> Symbol:
ret = self.get_symbol(
addr,
in_segment=in_segment,
type=type,
create=True,
define=define,

View File

@ -3,7 +3,9 @@
import hashlib
from typing import Dict, List, Union, Set, Any
import argparse
import pylibyaml
import spimdisasm
import rabbitizer
import tqdm
import yaml
import pickle
from colorama import Style, Fore
@ -13,8 +15,12 @@ from util import log
from util import options
from util import symbols
from util import palettes
from util import compiler
from util.symbols import Symbol
VERSION = "0.8.1.0"
from intervaltree import Interval, IntervalTree
VERSION = "0.9.0"
parser = argparse.ArgumentParser(
description="Split a rom given a rom, a config, and output directory"
@ -31,6 +37,9 @@ parser.add_argument(
linker_writer: LinkerWriter
config: Dict[str, Any]
segment_roms: IntervalTree = IntervalTree()
segment_rams: IntervalTree = IntervalTree()
def fmt_size(size):
if size > 1000000:
@ -42,6 +51,12 @@ def fmt_size(size):
def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:
global segment_roms
global segment_rams
segment_roms = IntervalTree()
segment_rams = IntervalTree()
seen_segment_names: Set[str] = set()
ret = []
@ -68,35 +83,42 @@ def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:
seen_segment_names.add(segment.name)
ret.append(segment)
if (
isinstance(segment.rom_start, int)
and isinstance(segment.rom_end, int)
and segment.rom_start != segment.rom_end
):
segment_roms.addi(segment.rom_start, segment.rom_end, segment)
if (
isinstance(segment.vram_start, int)
and isinstance(segment.vram_end, int)
and segment.vram_start != segment.vram_end
):
segment_rams.addi(segment.vram_start, segment.vram_end, segment)
return ret
def get_segment_symbols(segment, all_segments):
seg_syms = {}
other_syms = {}
def assign_symbols_to_segments():
seg_syms: dict[int, list[Symbol]] = {}
for symbol in symbols.all_symbols:
if symbols.is_symbol_isolated(symbol, all_segments) and not symbol.rom:
if segment.contains_vram(symbol.vram_start):
if symbol.vram_start not in seg_syms:
seg_syms[symbol.vram_start] = []
seg_syms[symbol.vram_start].append(symbol)
if symbol.rom:
cands = segment_roms[symbol.rom]
if len(cands) > 1:
log.error("multiple segments rom overlap symbol", symbol)
elif len(cands) == 0:
log.error("no segment rom overlaps symbol", symbol)
else:
if symbol.vram_start not in other_syms:
other_syms[symbol.vram_start] = []
other_syms[symbol.vram_start].append(symbol)
cand: Interval = cands.pop()
seg: Segment = cand.data
seg.add_symbol(symbol)
else:
if symbol.rom and segment.contains_rom(symbol.rom):
if symbol.vram_start not in seg_syms:
seg_syms[symbol.vram_start] = []
seg_syms[symbol.vram_start].append(symbol)
else:
if symbol.vram_start not in other_syms:
other_syms[symbol.vram_start] = []
other_syms[symbol.vram_start].append(symbol)
return seg_syms, other_syms
cands: Set[Interval] = segment_rams[symbol.vram_start]
segs: List[Segment] = [cand.data for cand in cands]
for seg in segs:
if not seg.get_exclusive_ram_id():
seg.add_symbol(symbol)
def do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached):
@ -152,10 +174,84 @@ def merge_configs(main_config, additional_config):
return main_config
def configure_disassembler():
# Configure spimdisasm
spimdisasm.common.GlobalConfig.PRODUCE_SYMBOLS_PLUS_OFFSET = True
spimdisasm.common.GlobalConfig.TRUST_USER_FUNCTIONS = True
spimdisasm.common.GlobalConfig.TRUST_JAL_FUNCTIONS = True
spimdisasm.common.GlobalConfig.GLABEL_ASM_COUNT = False
if options.rom_address_padding():
spimdisasm.common.GlobalConfig.ASM_COMMENT_OFFSET_WIDTH = 6
else:
spimdisasm.common.GlobalConfig.ASM_COMMENT_OFFSET_WIDTH = 0
# spimdisasm is not performing any analyzis on non-text sections so enabling this options is pointless
spimdisasm.common.GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_SECTION_TYPE = False
spimdisasm.common.GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_DATA_TYPE = False
spimdisasm.common.GlobalConfig.SYMBOL_FINDER_FILTERED_ADDRESSES_AS_HILO = False
rabbitizer.config.regNames_userFpcCsr = False
rabbitizer.config.regNames_vr4300Cop0NamedRegisters = False
rabbitizer.config.misc_opcodeLJust = options.mnemonic_ljust() - 1
rabbitizer.config.regNames_gprAbiNames = rabbitizer.Abi.fromStr(
options.get_mips_abi_gpr()
)
rabbitizer.config.regNames_fprAbiNames = rabbitizer.Abi.fromStr(
options.get_mips_abi_float_regs()
)
if options.get_endianess() == "big":
spimdisasm.common.GlobalConfig.ENDIAN = spimdisasm.common.InputEndian.BIG
else:
spimdisasm.common.GlobalConfig.ENDIAN = spimdisasm.common.InputEndian.LITTLE
rabbitizer.config.pseudos_pseudoMove = False
selectedCompiler = options.get_compiler()
if selectedCompiler == compiler.SN64:
rabbitizer.config.regNames_namedRegisters = False
rabbitizer.config.toolchainTweaks_sn64DivFix = True
rabbitizer.config.toolchainTweaks_treatJAsUnconditionalBranch = True
spimdisasm.common.GlobalConfig.ASM_COMMENT = False
spimdisasm.common.GlobalConfig.SYMBOL_FINDER_FILTERED_ADDRESSES_AS_HILO = False
spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.SN64
elif selectedCompiler == compiler.GCC:
rabbitizer.config.toolchainTweaks_treatJAsUnconditionalBranch = True
spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.GCC
elif selectedCompiler == compiler.IDO:
spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.IDO
spimdisasm.common.GlobalConfig.GP_VALUE = options.get_gp()
spimdisasm.common.GlobalConfig.ASM_TEXT_LABEL = options.get_asm_function_macro()
spimdisasm.common.GlobalConfig.ASM_DATA_LABEL = options.get_asm_data_macro()
spimdisasm.common.GlobalConfig.ASM_TEXT_END_LABEL = options.get_asm_end_label()
if spimdisasm.common.GlobalConfig.ASM_TEXT_LABEL == ".globl":
spimdisasm.common.GlobalConfig.ASM_TEXT_ENT_LABEL = ".ent"
spimdisasm.common.GlobalConfig.ASM_TEXT_FUNC_AS_LABEL = True
spimdisasm.common.GlobalConfig.LINE_ENDS = options.c_newline()
if options.get_platform() == "n64":
symbols.spim_context.fillDefaultBannedSymbols()
def brief_seg_name(seg: Segment, limit: int, ellipsis="") -> str:
s = seg.name.strip()
if len(s) > limit:
return s[:limit].strip() + ellipsis
return s
def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
global config
log.write(f"splat {VERSION}")
log.write(f"splat {VERSION} (powered by spimdisasm {spimdisasm.__version__})")
# Load config
config = {}
@ -210,21 +306,29 @@ def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
"__options__": config.get("options"),
}
configure_disassembler()
# Initialize segments
all_segments = initialize_segments(config["segments"])
# Load and process symbols
symbols.initialize(all_segments)
# Assign symbols to segments
assign_symbols_to_segments()
if options.mode_active("code"):
log.write("Loading and processing symbols")
symbols.initialize(all_segments)
symbols.initialize_spim_context(all_segments)
# Resolve raster/palette siblings
if options.mode_active("img"):
palettes.initialize(all_segments)
# Scan
log.write("Starting scan")
for segment in all_segments:
scan_bar = tqdm.tqdm(all_segments, total=len(all_segments))
for segment in scan_bar:
assert isinstance(segment, Segment)
scan_bar.set_description(f"Scanning {brief_seg_name(segment, 20)}")
typ = segment.type
if segment.type == "bin" and segment.is_name_default():
typ = "unk"
@ -241,13 +345,6 @@ def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
if segment.cache() == cache.get(segment.unique_id()):
continue
if segment.needs_symbols:
segment_symbols, other_symbols = get_segment_symbols(
segment, all_segments
)
segment.given_seg_symbols = segment_symbols
segment.given_ext_symbols = other_symbols
segment.did_run = True
segment.scan(rom_bytes)
@ -255,11 +352,12 @@ def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
seg_split[typ] += 1
log.dot(status=segment.status())
# Split
log.write("Starting split")
for segment in all_segments:
for segment in tqdm.tqdm(
all_segments,
total=len(all_segments),
desc=f"Splitting {brief_seg_name(segment, 20)}",
):
if use_cache:
cached = segment.cache()
@ -274,12 +372,14 @@ def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
if segment.should_split():
segment.split(rom_bytes)
log.dot(status=segment.status())
if options.mode_active("ld"):
global linker_writer
linker_writer = LinkerWriter()
for segment in all_segments:
for segment in tqdm.tqdm(
all_segments,
total=len(all_segments),
desc=f"Writing linker script {brief_seg_name(segment, 20)}",
):
linker_writer.add(segment)
linker_writer.save_linker_script()
linker_writer.save_symbol_header()
@ -300,22 +400,27 @@ def main(config_path, base_dir, target_path, modes, verbose, use_cache=True):
for s in symbols.all_symbols
if s.referenced and not s.defined and not s.dead and s.type == "func"
]
if len(to_write) > 0:
with open(options.get_undefined_funcs_auto_path(), "w", newline="\n") as f:
for symbol in to_write:
f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n")
to_write.sort(key=lambda x: x.vram_start)
with open(options.get_undefined_funcs_auto_path(), "w", newline="\n") as f:
for symbol in to_write:
f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n")
# write undefined_syms_auto.txt
if options.get_create_undefined_syms_auto():
to_write = [
s
for s in symbols.all_symbols
if s.referenced and not s.defined and not s.dead and not s.type == "func"
if s.referenced
and not s.defined
and not s.dead
and s.type not in {"func", "label", "jtbl_label"}
]
if len(to_write) > 0:
with open(options.get_undefined_syms_auto_path(), "w", newline="\n") as f:
for symbol in to_write:
f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n")
to_write.sort(key=lambda x: x.vram_start)
with open(options.get_undefined_syms_auto_path(), "w", newline="\n") as f:
for symbol in to_write:
f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n")
# print warnings during split
for segment in all_segments:

View File

@ -24,7 +24,9 @@ SN64 = Compiler(
c_newline="\r\n",
)
compiler_for_name = {"GCC": GCC, "SN64": SN64}
IDO = Compiler("IDO")
compiler_for_name = {"GCC": GCC, "SN64": SN64, "IDO": IDO}
def for_name(name: str) -> Compiler:

View File

@ -31,13 +31,6 @@ def parsing_error_preamble(path, line_num, line):
write(f"\t{line}")
def dot(status: Status = None):
global newline
print(status_to_ansi(status) + ".", end="")
newline = False
def status_to_ansi(status: Status):
if status == "ok":
return Fore.GREEN

View File

@ -1,22 +1,25 @@
#! /usr/bin/env python3
from capstone import *
from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS64, CS_MODE_BIG_ENDIAN
from capstone.mips import *
import argparse
import spimdisasm
import rabbitizer
def int_any_base(x):
return int(x, 0)
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN)
parser = argparse.ArgumentParser(
description="Given a rom and start offset, find where the code ends"
)
parser.add_argument("rom", help="path to a .z64 rom")
parser.add_argument("start", help="start offset")
parser.add_argument("--end", help="end offset", default=None)
parser.add_argument("start", help="start offset", type=int_any_base)
parser.add_argument("--end", help="end offset", default=None, type=int_any_base)
parser.add_argument(
"--vram", help="vram address to start disassembly at", default="0x80000000"
"--vram",
help="vram address to start disassembly at",
default="0x80000000",
type=int_any_base,
)
@ -24,28 +27,35 @@ def run(rom_bytes, start_offset, vram, end_offset=None):
rom_addr = start_offset
last_return = rom_addr
for insn in md.disasm(rom_bytes[start_offset:], vram):
if insn.mnemonic == "jr" and insn.op_str == "$ra":
wordList = spimdisasm.common.Utils.bytesToBEWords(rom_bytes[start_offset:])
for word in wordList:
insn = rabbitizer.Instruction(word)
if not insn.isImplemented():
break
if insn.isJrRa():
last_return = rom_addr
rom_addr += 4
if end_offset and rom_addr >= end_offset:
break
return last_return + (0x10 - (last_return % 0x10))
# align to next 0x10 boundary
end = last_return + 0x10
end -= end % 0x10
return end
def main():
args = parser.parse_args()
rom_bytes = open(args.rom, "rb").read()
start = int(args.start, 0)
end = None
vram = int(args.vram, 0)
with open(args.rom, "rb") as f:
rom_bytes = f.read()
if args.end:
end = int(args.end, 0)
start = args.start
end = args.end
vram = args.vram
print(f"{run(rom_bytes, start, vram, end):X}")
print(f"0x{run(rom_bytes, start, vram, end):X}")
if __name__ == "__main__":

View File

@ -1,21 +1,28 @@
#! /usr/bin/env python3
from dataclasses import dataclass
import sys
import argparse
import itertools
import struct
import spimdisasm
import rabbitizer
from pathlib import Path
import hashlib
import zlib
from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS64, CS_MODE_BIG_ENDIAN
parser = argparse.ArgumentParser(description="Gives information on N64 roms")
parser.add_argument("rom", help="path to an N64 rom")
parser.add_argument(
"--header-encoding",
help="Text encoding the game header is using; see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings",
dest="header_encoding",
help=(
"Text encoding the game header is using;"
" see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings"
),
)
country_codes = {
@ -42,27 +49,34 @@ country_codes = {
0x59: "European",
}
@dataclass
class CIC:
ntsc_name: str
pal_name: str
offset: int
crc_to_cic = {
0x6170A4A1: {"ntsc-name": "6101", "pal-name": "7102", "offset": 0x000000},
0x90BB6CB5: {"ntsc-name": "6102", "pal-name": "7101", "offset": 0x000000},
0x0B050EE0: {"ntsc-name": "6103", "pal-name": "7103", "offset": 0x100000},
0x98BC2C86: {"ntsc-name": "6105", "pal-name": "7105", "offset": 0x000000},
0xACC8580A: {"ntsc-name": "6106", "pal-name": "7106", "offset": 0x200000},
0x00000000: {"ntsc-name": "unknown", "pal-name": "unknown", "offset": 0x0000000},
0x6170A4A1: CIC("6101", "7102", 0x000000),
0x90BB6CB5: CIC("6102", "7101", 0x000000),
0x0B050EE0: CIC("6103", "7103", 0x100000),
0x98BC2C86: CIC("6105", "7105", 0x000000),
0xACC8580A: CIC("6106", "7106", 0x200000),
}
unknown_cic = CIC("unknown", "unknown", 0x0000000)
def swap_bytes(data):
return bytes(
itertools.chain.from_iterable(
struct.pack(">H", x) for x, in struct.iter_unpack("<H", data)
struct.pack(">H", x) for (x,) in struct.iter_unpack("<H", data)
)
)
def read_rom(rom_path):
with open(rom_path, "rb") as f:
rom_bytes = f.read()
def read_rom(rom_path: Path):
rom_bytes = rom_path.read_bytes()
if rom_path.suffix.lower() == ".n64":
print("Warning: Input file has .n64 suffix, byte-swapping!")
@ -70,24 +84,21 @@ def read_rom(rom_path):
as_z64 = rom_path.with_suffix(".z64")
if not as_z64.exists():
print(f"Writing down {as_z64}")
with open(as_z64, "wb") as o:
o.write(rom_bytes)
as_z64.write_bytes(rom_bytes)
return rom_bytes
def get_cic(rom_bytes):
crc = zlib.crc32(rom_bytes[0x40:0x1000])
if crc in crc_to_cic:
return crc_to_cic[crc]
else:
return crc_to_cic[0]
def get_cic(rom_bytes: bytes):
ipl3_crc = zlib.crc32(rom_bytes[0x40:0x1000])
return crc_to_cic.get(ipl3_crc, unknown_cic)
def get_entry_point(program_counter, cic):
return program_counter - cic["offset"]
def get_entry_point(program_counter: int, cic: CIC):
return program_counter - cic.offset
def guess_header_encoding(rom_bytes):
def guess_header_encoding(rom_bytes: bytes):
header = rom_bytes[0x20:0x34]
encodings = ["ASCII", "shift_jis", "euc-jp"]
for encoding in encodings:
@ -98,12 +109,11 @@ def guess_header_encoding(rom_bytes):
# we guessed wrong...
pass
print("Unknown header encoding, please raise an Issue with us")
exit(1)
sys.exit("Unknown header encoding, please raise an Issue with us")
def get_info(rom_path, rom_bytes=None, header_encoding=None):
if not rom_bytes:
def get_info(rom_path: Path, rom_bytes: bytes = None, header_encoding=None):
if rom_bytes is None:
rom_bytes = read_rom(rom_path)
if header_encoding is None:
@ -112,31 +122,25 @@ def get_info(rom_path, rom_bytes=None, header_encoding=None):
return get_info_bytes(rom_bytes, header_encoding)
def get_info_bytes(rom_bytes, header_encoding):
program_counter = int(rom_bytes[0x8:0xC].hex(), 16)
def get_info_bytes(rom_bytes: bytes, header_encoding):
(program_counter,) = struct.unpack(">I", rom_bytes[0x8:0xC])
libultra_version = chr(rom_bytes[0xF])
crc1 = rom_bytes[0x10:0x14].hex().upper()
crc2 = rom_bytes[0x14:0x18].hex().upper()
checksum = rom_bytes[0x10:0x18].hex().upper()
try:
name = rom_bytes[0x20:0x34].decode(header_encoding).strip()
except:
print(
"splat could not decode the game name; try using a different encoding by passing the --header-encoding argument (see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings)"
sys.exit(
"splat could not decode the game name;"
" try using a different encoding by passing the --header-encoding argument"
" (see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings)"
)
exit(1)
country_code = rom_bytes[0x3E]
cic = get_cic(rom_bytes)
entry_point = get_entry_point(program_counter, cic)
# TODO: add support for
# compression_formats = []
# for format in ["Yay0", "vpk0"]:
# if rom_bytes.find(bytes(format, "ASCII")) != -1:
# compression_formats.append(format)
compiler = get_compiler_info(rom_bytes, entry_point, print_result=False)
sha1 = hashlib.sha1(rom_bytes).hexdigest()
@ -146,8 +150,7 @@ def get_info_bytes(rom_bytes, header_encoding):
header_encoding,
country_code,
libultra_version,
crc1,
crc2,
checksum,
cic,
entry_point,
len(rom_bytes),
@ -159,15 +162,14 @@ def get_info_bytes(rom_bytes, header_encoding):
class N64Rom:
def __init__(
self,
name,
name: str,
header_encoding,
country_code,
libultra_version,
crc1,
crc2,
cic,
entry_point,
size,
checksum,
cic: CIC,
entry_point: int,
size: int,
compiler,
sha1,
):
@ -175,8 +177,7 @@ class N64Rom:
self.header_encoding = header_encoding
self.country_code = country_code
self.libultra_version = libultra_version
self.crc1 = crc1
self.crc2 = crc2
self.checksum = checksum
self.cic = cic
self.entry_point = entry_point
self.size = size
@ -188,28 +189,33 @@ class N64Rom:
def get_compiler_info(rom_bytes, entry_point, print_result=True):
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN)
md.detail = True
jumps = 0
branches = 0
for insn in md.disasm(rom_bytes[0x1000:], entry_point):
if insn.mnemonic == "j":
vram = entry_point
wordList = spimdisasm.common.Utils.bytesToBEWords(rom_bytes[0x1000:])
for word in wordList:
insn = rabbitizer.Instruction(word)
if not insn.isImplemented():
break
if insn.uniqueId == rabbitizer.InstrId.cpu_j:
jumps += 1
elif insn.mnemonic == "b":
elif insn.uniqueId == rabbitizer.InstrId.cpu_b:
branches += 1
compiler = "IDO" if branches > jumps else "GCC"
if print_result:
print(
f"{branches} branches and {jumps} jumps detected in the first code segment. Compiler is most likely {compiler}"
f"{branches} branches and {jumps} jumps detected in the first code segment."
f" Compiler is most likely {compiler}"
)
return compiler
# TODO: support .n64 extension
def main():
rabbitizer.config.pseudos_pseudoB = True
args = parser.parse_args()
rom_bytes = read_rom(Path(args.rom))
rom = get_info(Path(args.rom), rom_bytes, args.header_encoding)
@ -217,9 +223,8 @@ def main():
print("Image name: " + rom.name)
print("Country code: " + chr(rom.country_code) + " - " + rom.get_country_name())
print("Libultra version: " + rom.libultra_version)
print("CRC1: " + rom.crc1)
print("CRC2: " + rom.crc2)
print("CIC: " + rom.cic["ntsc-name"] + " / " + rom.cic["pal-name"])
print("Checksum: " + rom.checksum)
print("CIC: " + rom.cic.ntsc_name + " / " + rom.cic.pal_name)
print("RAM entry point: " + hex(rom.entry_point))
print("Header encoding: " + rom.header_encoding)
print("")

View File

@ -226,10 +226,16 @@ def get_subalign() -> int:
return opts.get("subalign", 16)
# Determines whether to automatically configure the linker script to link against common sections for all files
# when the yaml doesn't have specific configurations for these sections. See release notes for details
def auto_all_sections() -> bool:
return opts.get("auto_all_sections", False)
# The following option determines whether to automatically configure the linker script to link against
# specified sections for all "base" (asm/c) files when the yaml doesn't have manual configurations
# for these sections.
def auto_all_sections() -> List[str]:
val = opts.get("auto_all_sections", [".data", ".rodata", ".bss"])
if not isinstance(val, list):
raise RuntimeError(
'auto_all_sections must be a list (for example, [".data", ".rodata", ".bss"])'
)
return val
# Determines the desired path to the linker symbol header, which exposes externed definitions for all segment ram/rom start/end locations
@ -268,10 +274,12 @@ def ld_section_labels() -> List[str]:
def get_create_c_files() -> bool:
return opts.get("create_c_files", True)
# Determines whether to "auto-decompile" empty functions
def get_auto_decompile_empty_functions() -> bool:
return opts.get("auto_decompile_empty_functions", True)
# Determines whether to detect matched/unmatched functions in existing c files
# so we can avoid creating .s files for already-decompiled functions
def do_c_func_detection() -> bool:
@ -287,6 +295,16 @@ def c_newline() -> str:
# (Dis)assembly-related options
################################################################################
# The following options determine the format that symbols should be named by default
def get_symbol_name_format() -> str:
return opts.get("symbol_name_format", "$VRAM")
# Same as above but for symbols with no rom address
def get_symbol_name_format_no_rom() -> str:
return opts.get("symbol_name_format_no_rom", "$VRAM_$SEG")
# Determines whether to detect and hint to the user about likely file splits when disassembling
def find_file_boundaries() -> bool:
return opts.get("find_file_boundaries", True)
@ -332,6 +350,20 @@ def rom_address_padding() -> bool:
return opts.get("rom_address_padding", False)
# Determines which ABI names to use for general purpose registers
# Valid values: 'numeric', 'o32', 'n32', 'n64'
def get_mips_abi_gpr() -> str:
return opts.get("mips_abi_gpr", "o32")
# Determines which ABI names to use for floating point registers
# Valid values: 'numeric', 'o32', 'n32', 'n64'
# o32 is highly recommended, as it provides logically named registers for floating point instructions
# For more info, see https://gist.github.com/EllipticEllipsis/27eef11205c7a59d8ea85632bc49224d
def get_mips_abi_float_regs() -> str:
return opts.get("mips_abi_float_regs", "numeric")
################################################################################
# N64-specific options
################################################################################
@ -341,6 +373,16 @@ def get_header_encoding() -> str:
return opts.get("header_encoding", "ASCII")
# Determines the type gfx ucode (used by gfx segments)
# Valid options are ['f3d', 'f3db', 'f3dex', 'f3dexb', 'f3dex2']
def get_gfx_ucode() -> str:
valid_options = ["f3d", "f3db", "f3dex", "f3dexb", "f3dex2"]
ret = opts.get("gfx_ucode", "f3dex2")
if ret not in valid_options:
log.error(f"Invalid gfx_ucode: {ret}. Valid options are: {valid_options}")
return ret
################################################################################
# Compiler-specific options
################################################################################

View File

@ -1,7 +1,11 @@
import dataclasses
from typing import Optional
@dataclasses.dataclass
class Range:
def __init__(self, start=None, end=None):
self.start = start
self.end = end
start: Optional[int] = None
end: Optional[int] = None
def has_start(self):
return self.start is not None

View File

@ -1,12 +1,21 @@
from dataclasses import dataclass
from typing import Dict, List, Optional
from typing import Dict, List, Optional, TYPE_CHECKING, Set
import spimdisasm
import rabbitizer
import tqdm
# circular import
if TYPE_CHECKING:
from segtypes.segment import Segment
from capstone import CsInsn
from util import options, log
all_symbols: "List[Symbol]" = []
symbol_ranges: "List[Symbol]" = []
sym_isolated_map: "Dict[Symbol, bool]" = {}
all_symbols: List["Symbol"] = []
all_symbols_dict: Dict[int, List["Symbol"]] = {}
ignored_addresses: Set[int] = set()
symbol_ranges: List["Symbol"] = []
# Initialize a spimdisasm context, used to store symbols and functions
spim_context = spimdisasm.common.Context()
TRUEY_VALS = ["true", "on", "yes", "y"]
FALSEY_VALS = ["false", "off", "no", "n"]
@ -20,19 +29,37 @@ def is_falsey(str: str) -> bool:
return str.lower() in FALSEY_VALS
def initialize(all_segments):
def add_symbol(sym: "Symbol"):
all_symbols.append(sym)
if sym.vram_start is not None:
if sym.vram_start not in all_symbols_dict:
all_symbols_dict[sym.vram_start] = []
all_symbols_dict[sym.vram_start].append(sym)
def initialize(all_segments: "List[Segment]"):
global all_symbols
global all_symbols_dict
global symbol_ranges
all_symbols = []
all_symbols_dict = {}
symbol_ranges = []
def get_seg_for_name(name: str) -> Optional["Segment"]:
for segment in all_segments:
if segment.name == name:
return segment
return None
# Manual list of func name / addrs
for path in options.get_symbol_addrs_paths():
if path.exists():
with open(path) as f:
sym_addrs_lines = f.readlines()
for line_num, line in enumerate(sym_addrs_lines):
for line_num, line in enumerate(
tqdm.tqdm(sym_addrs_lines, desc=f"Loading symbols ({path.stem})")
):
line = line.strip()
if not line == "" and not line.startswith("//"):
comment_loc = line.find("//")
@ -59,10 +86,11 @@ def initialize(all_segments):
sym = Symbol(addr, given_name=name)
ignore_sym = False
if line_ext:
for info in line_ext.split(" "):
if ":" in info:
if info.count(':') > 1:
if info.count(":") > 1:
log.parsing_error_preamble(path, line_num, line)
log.write(f"Too many ':'s in '{info}'")
log.error("")
@ -70,14 +98,17 @@ def initialize(all_segments):
attr_name, attr_val = info.split(":")
if attr_name == "":
log.parsing_error_preamble(path, line_num, line)
log.write(f"Missing attribute name in '{info}', is there extra whitespace?")
log.write(
f"Missing attribute name in '{info}', is there extra whitespace?"
)
log.error("")
if attr_val == "":
log.parsing_error_preamble(path, line_num, line)
log.write(f"Missing attribute value in '{info}', is there extra whitespace?")
log.write(
f"Missing attribute value in '{info}', is there extra whitespace?"
)
log.error("")
# Non-Boolean attributes
try:
if attr_name == "type":
@ -86,12 +117,27 @@ def initialize(all_segments):
continue
if attr_name == "size":
size = int(attr_val, 0)
sym.size = size
sym.given_size = size
continue
if attr_name == "rom":
rom_addr = int(attr_val, 0)
sym.rom = rom_addr
continue
if attr_name == "segment":
seg = get_seg_for_name(attr_val)
if seg is None:
log.parsing_error_preamble(
path, line_num, line
)
log.write(
f"Cannot find segment '{attr_val}'"
)
log.error("")
else:
# Add segment to symbol, symbol to segment
sym.segment = seg
seg.add_symbol(sym)
continue
except:
log.parsing_error_preamble(path, line_num, line)
log.write(
@ -115,39 +161,180 @@ def initialize(all_segments):
)
log.write([*TRUEY_VALS, *FALSEY_VALS])
log.error("")
else:
if attr_name == "dead":
sym.dead = tf_val
continue
if attr_name == "defined":
sym.defined = tf_val
continue
if attr_name == "extract":
sym.extract = tf_val
continue
if attr_name == "ignore":
ignore_sym = tf_val
continue
if ignore_sym:
ignored_addresses.add(sym.vram_start)
ignore_sym = False
continue
if attr_name == "dead":
sym.dead = tf_val
continue
if attr_name == "defined":
sym.defined = tf_val
continue
if attr_name == "extract":
sym.extract = tf_val
continue
all_symbols.append(sym)
sym.user_declared = True
add_symbol(sym)
# Symbol ranges
if sym.size > 4:
symbol_ranges.append(sym)
is_symbol_isolated(sym, all_segments)
def initialize_spim_context(all_segments: "List[Segment]") -> None:
global_vrom_start = None
global_vrom_end = None
global_vram_start = None
global_vram_end = None
def is_symbol_isolated(symbol, all_segments):
if symbol in sym_isolated_map:
return sym_isolated_map[symbol]
relevant_segs = 0
spim_context.bannedSymbols |= ignored_addresses
for segment in all_segments:
if segment.contains_vram(symbol.vram_start):
relevant_segs += 1
if relevant_segs > 1:
break
if segment.type == "code":
# We only care about the VRAMs of code segments
if isinstance(segment.vram_start, int) and isinstance(
segment.vram_end, int
):
ram_id = segment.get_exclusive_ram_id()
if ram_id is None:
if global_vram_start is None:
global_vram_start = segment.vram_start
else:
if segment.vram_start < global_vram_start:
global_vram_start = segment.vram_start
sym_isolated_map[symbol] = relevant_segs < 2
return sym_isolated_map[symbol]
if global_vram_end is None:
global_vram_end = segment.vram_end
else:
if global_vram_end < segment.vram_end:
global_vram_end = segment.vram_end
if isinstance(segment.rom_start, int):
if global_vrom_start is None:
global_vrom_start = segment.rom_start
else:
if segment.rom_start < global_vrom_start:
global_vrom_start = segment.rom_start
if isinstance(segment.rom_end, int):
if global_vrom_end is None:
global_vrom_end = segment.rom_end
else:
if global_vrom_end < segment.rom_end:
global_vrom_end = segment.rom_end
else:
spim_context.addOverlaySegment(
ram_id,
segment.rom_start,
segment.rom_end,
segment.vram_start,
segment.vram_end,
)
if (
global_vram_start is not None
and global_vram_end is not None
and global_vrom_start is not None
and global_vrom_end is not None
):
spim_context.globalSegment.changeRanges(
global_vrom_start, global_vrom_end, global_vram_start, global_vram_end
)
def add_symbol_to_spim_section(
section: spimdisasm.common.ElementBase, sym: "Symbol"
) -> spimdisasm.common.ContextSymbol:
if sym.type == "func":
context_sym = section.addFunction(
sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom
)
elif sym.type == "jtbl":
context_sym = section.addJumpTable(
sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom
)
elif sym.type == "jtbl_label":
context_sym = section.addJumpTableLabel(
sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom
)
elif sym.type == "label":
context_sym = section.addBranchLabel(
sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom
)
else:
context_sym = section.addSymbol(
sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom
)
if sym.type and sym.type != "unknown":
context_sym.type = sym.type
if sym.user_declared:
context_sym.isUserDeclared = True
if sym.defined:
context_sym.isDefined = True
if sym.rom is not None:
context_sym.vromAddress = sym.rom
if sym.given_size is not None:
context_sym.size = sym.size
context_sym.setNameGetCallbackIfUnset(lambda _: sym.name)
return context_sym
def create_symbol_from_spim_symbol(
segment: "Segment", context_sym: spimdisasm.common.ContextSymbol
) -> "Symbol":
in_segment = False
sym_type = None
if context_sym.type == spimdisasm.common.SymbolSpecialType.jumptable:
in_segment = True
sym_type = "jtbl"
elif context_sym.type == spimdisasm.common.SymbolSpecialType.function:
sym_type = "func"
elif context_sym.type == spimdisasm.common.SymbolSpecialType.branchlabel:
in_segment = True
sym_type = "label"
elif context_sym.type == spimdisasm.common.SymbolSpecialType.jumptablelabel:
in_segment = True
sym_type = "jtbl_label"
if not in_segment:
if (
context_sym.overlayCategory is None
and segment.get_exclusive_ram_id() is None
):
in_segment = segment.contains_vram(context_sym.vram)
elif context_sym.overlayCategory == segment.get_exclusive_ram_id():
if context_sym.vromAddress is not None:
in_segment = segment.contains_rom(context_sym.vromAddress)
else:
in_segment = segment.contains_vram(context_sym.vram)
sym = segment.create_symbol(
context_sym.vram, in_segment, type=sym_type, reference=True
)
# To keep the symbol name in sync between splat and spimdisasm
context_sym.setNameGetCallback(lambda _: sym.name)
if context_sym.size is not None:
sym.given_size = context_sym.getSize()
if context_sym.vromAddress is not None:
sym.rom = context_sym.getVrom()
if context_sym.isDefined:
sym.defined = True
if context_sym.referenceCounter > 0:
sym.referenced = True
return sym
def retrieve_from_ranges(vram, rom=None):
@ -169,36 +356,79 @@ def retrieve_from_ranges(vram, rom=None):
return None
@dataclass
class Instruction:
instruction: CsInsn
mnemonic: str
op_str: str
rom_addr: int
is_gp: bool = False
is_hi: bool = False
is_lo: bool = False
hi_lo_sym: Optional["Symbol"] = None
sym_offset_str: str = ""
hi_lo_reg: str = ""
class Symbol:
def __init__(
self,
vram: int,
given_name: Optional[str] = None,
rom: Optional[int] = None,
type: Optional[str] = "unknown",
given_size: Optional[int] = None,
segment: Optional["Segment"] = None,
):
self.defined: bool = False
self.referenced: bool = False
self.vram_start = vram
self.rom = rom
self.type = type
self.given_size = given_size
self.given_name = given_name
self.access_mnemonic: Optional[rabbitizer.Enum] = None
self.disasm_str: Optional[str] = None
self.dead: bool = False
self.extract: bool = True
self.user_declared: bool = False
self.segment: Optional["Segment"] = segment
def __str__(self):
return self.name
def format_name(self, format: str) -> str:
ret = format
ret = ret.replace("$VRAM", f"{self.vram_start:08X}")
if "$ROM" in ret:
if not isinstance(self.rom, int):
log.error(
f"Attempting to rom-name a symbol with no ROM address: {self.vram_start:X} typed {self.type}"
)
ret = ret.replace("$ROM", f"{self.rom:X}")
if "$SEG" in ret:
if self.segment is None:
# This probably is fine - we can't expect every symbol to have a segment. Fall back to just the ram address
return f"{self.vram_start:X}"
assert self.segment is not None
ret = ret.replace("$SEG", self.segment.name)
return ret
@property
def default_name(self) -> str:
suffix = f"_{self.vram_start:X}"
if self.in_overlay:
suffix += f"_{self.rom:X}"
if self.segment:
if isinstance(self.rom, int):
suffix = self.format_name(self.segment.symbol_name_format)
else:
suffix = self.format_name(self.segment.symbol_name_format_no_rom)
else:
if isinstance(self.rom, int):
suffix = self.format_name(options.get_symbol_name_format())
else:
suffix = self.format_name(options.get_symbol_name_format_no_rom())
if self.type == "func":
prefix = "func"
elif self.type == "jtbl":
prefix = "jtbl"
elif self.type == "jtbl_label":
return f"L{suffix}"
elif self.type == "label":
return f".L{suffix}"
else:
prefix = "D"
return prefix + suffix
return f"{prefix}_{suffix}"
@property
def rom_end(self):
@ -212,31 +442,14 @@ class Symbol:
def name(self) -> str:
return self.given_name if self.given_name else self.default_name
@property
def size(self) -> int:
if self.given_size is not None:
return self.given_size
return 4
def contains_vram(self, offset):
return offset >= self.vram_start and offset < self.vram_end
def contains_rom(self, offset):
return offset >= self.rom and offset < self.rom_end
def __init__(
self,
vram,
given_name: str = "",
rom=None,
type="unknown",
in_overlay=False,
size=4,
):
self.defined = False
self.referenced = False
self.vram_start = vram
self.rom = rom
self.type = type
self.in_overlay = in_overlay
self.size = size
self.given_name: str = given_name
self.insns: List[Instruction] = []
self.access_mnemonic = None
self.disasm_str = None
self.dead = False
self.extract = True

View File

@ -1,7 +1,6 @@
from yaml.loader import Loader
from segtypes.n64.segment import N64Segment
from util import options
import yaml
import yaml as yaml_loader
class N64SegPm_effect_loads(N64Segment):
effects = []
@ -47,11 +46,40 @@ glabel {name}
def effect_path(self, effect):
return options.get_build_path() / "asm" / "effects" / f"{effect}.s"
def __init__(self, rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml):
super().__init__(rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml)
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
with open(options.get_asm_path() / ".." / "effects.yaml") as f:
self.effects = yaml.load(f.read(), Loader=yaml.SafeLoader)
self.effects = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes):
for i, effect in enumerate(self.effects):

View File

@ -1,7 +1,7 @@
from yaml.loader import Loader
from segtypes.n64.segment import N64Segment
from util import options
import yaml
import yaml as yaml_loader
class N64SegPm_effect_shims(N64Segment):
shims = []
@ -27,11 +27,40 @@ glabel {name}
def shim_path(self, shim):
return options.get_build_path() / "asm" / "effect_shims" / f"{shim}.s"
def __init__(self, rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml):
super().__init__(rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml)
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
with open(options.get_asm_path() / ".." / "effect_shims.yaml") as f:
self.shims = yaml.load(f.read(), Loader=yaml.SafeLoader)
self.shims = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes):
for i, shim in enumerate(self.shims):

View File

@ -38,8 +38,37 @@ def add_file_ext(name: str) -> str:
return name + ".bin"
class N64SegPm_map_data(N64Segment):
def __init__(self, rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yaml):
super().__init__(rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yaml)
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.files = yaml["files"]

View File

@ -5,7 +5,7 @@ from util import options
import re
import pylibyaml
import yaml
import yaml as yaml_loader
CHARSET = {
0x00: "[NOTE]",
@ -367,13 +367,42 @@ CHARSET_CREDITS = {
}
class N64SegPm_msg(N64Segment):
def __init__(self, rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml):
super().__init__(rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml)
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.files = yml.get("files", []) if isinstance(yml, dict) else []
self.files = yaml.get("files", []) if isinstance(yaml, dict) else []
with (Path(__file__).parent / f"{self.name}.yaml").open("r") as f:
self.msg_names = yaml.load(f.read(), Loader=yaml.SafeLoader)
self.msg_names = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes):
data = rom_bytes[self.rom_start: self.rom_end]

View File

@ -10,7 +10,7 @@ import xml.etree.ElementTree as ET
import struct
import pylibyaml
import yaml
import yaml as yaml_loader
class Sprite:
def __init__(self):
@ -253,13 +253,42 @@ class Component:
class N64SegPm_npc_sprites(N64Segment):
DEFAULT_SPRITE_NAMES = [f"{i:02X}" for i in range(0xEA)]
def __init__(self, rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml):
super().__init__(rom_start, rom_end, type, name, vram_start, extract, given_subalign, given_is_overlay, given_dir, args, yml)
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format,
symbol_name_format_no_rom,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
extract,
given_subalign,
exclusive_ram_id,
given_dir,
symbol_name_format=symbol_name_format,
symbol_name_format_no_rom=symbol_name_format_no_rom,
args=args,
yaml=yaml,
)
self.files = yml["files"]
self.files = yaml["files"]
with (Path(__file__).parent / f"{self.name}.yaml").open("r") as f:
self.sprite_cfg = yaml.load(f.read(), Loader=yaml.SafeLoader)
self.sprite_cfg = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes):
out_dir = options.get_asset_path() / self.dir / self.name

View File

@ -129,6 +129,7 @@ def read_elf():
continue
if "/" in name or \
"." in name or \
name in ignores or \
name.startswith("_") or \
name.startswith("jtbl_") or \

View File

@ -17,7 +17,9 @@ options:
asset_path: assets/jp
build_path: ver/jp/build
cache_path: ver/jp/.splat_cache
create_undefined_funcs_auto: False
undefined_funcs_auto_path: ver/jp/undefined_funcs_auto.txt
create_undefined_syms_auto: False
undefined_syms_auto_path: ver/jp/undefined_syms_auto.txt
asset_stack:
- jp

View File

@ -0,0 +1,27 @@
.include "macro.inc"
.section .data
dlabel D_8014C5A0
.word 0xFFF40000, 0x00000000, 0x23002300, 0x000000FF, 0x000B0000, 0x00000000, 0x20002300, 0x000000FF, 0x000B0017, 0x00000000, 0x20002000, 0x000000FF, 0xFFF40017, 0x00000000, 0x23002000, 0x000000FF
dlabel D_8014C5E0
.word 0xFFF00000, 0x00000000, 0x24002400, 0x000000FF, 0x000F0000, 0x00000000, 0x20002400, 0x000000FF, 0x000F001F, 0x00000000, 0x20002000, 0x000000FF, 0xFFF0001F, 0x00000000, 0x24002000, 0x000000FF
dlabel D_8014C620
.word 0xE7000000, 0x00000000, 0xD7000002, 0xFFFFFFFF, 0xFCFFFFFF, 0xFFFCF279, 0xE3000C00, 0x00080000, 0xE3000D01, 0x00000000, 0xE3000F00, 0x00000000, 0xE3001001, 0x00000000, 0xE3001201, 0x00002000, 0xE3001402, 0x00000C00, 0xE3001001, 0x00008000, 0xDF000000, 0x00000000
dlabel D_8014C678
.word 0xD9DDFBFF, 0x00000000, 0x01004008, D_8014C5A0, 0x06000204, 0x00000406, 0xE7000000, 0x00000000, 0xDF000000, 0x00000000
dlabel D_8014C6A0
.word 0xD9DDFBFF, 0x00000000, 0x01004008, D_8014C5E0, 0x06000204, 0x00000406, 0xE7000000, 0x00000000, 0xDF000000, 0x00000000
dlabel D_8014C6C8
.word 0xFFFFFF00, 0xFFFFFF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000
dlabel D_8014C6E0
.short 0x0020, 0x0028
dlabel D_8014C6E4
.short 0x0008, 0x0004, 0x0000, 0x0000, 0x0000, 0x0000

View File

@ -1,182 +0,0 @@
.set noat # allow manual use of $at
.set noreorder # don't insert nops after branches
glabel func_8002D160
/* 8560 8002D160 27BDFFC0 */ addiu $sp, $sp, -0x40
/* 8564 8002D164 AFB60030 */ sw $s6, 0x30($sp)
/* 8568 8002D168 3C16759A */ lui $s6, 0x759a
/* 856C 8002D16C 26D6F6D8 */ addiu $s6, $s6, -0x928
/* 8570 8002D170 AFB5002C */ sw $s5, 0x2c($sp)
/* 8574 8002D174 3C15F79E */ lui $s5, %hi(D_F79DDD0F)
/* 8578 8002D178 26B5DD0F */ addiu $s5, $s5, %lo(D_F79DDD0F)
/* 857C 8002D17C AFB30024 */ sw $s3, 0x24($sp)
/* 8580 8002D180 3C130B11 */ lui $s3, 0xb11
/* 8584 8002D184 36732D28 */ ori $s3, $s3, 0x2d28
/* 8588 8002D188 AFB00018 */ sw $s0, 0x18($sp)
/* 858C 8002D18C 0000802D */ daddu $s0, $zero, $zero
/* 8590 8002D190 3C05B000 */ lui $a1, 0xb000
/* 8594 8002D194 34A50D10 */ ori $a1, $a1, 0xd10
/* 8598 8002D198 3C04800A */ lui $a0, %hi(nuPiCartHandle)
/* 859C 8002D19C 8C84A638 */ lw $a0, %lo(nuPiCartHandle)($a0)
/* 85A0 8002D1A0 27A60010 */ addiu $a2, $sp, 0x10
/* 85A4 8002D1A4 AFB20020 */ sw $s2, 0x20($sp)
/* 85A8 8002D1A8 0200902D */ daddu $s2, $s0, $zero
/* 85AC 8002D1AC AFB40028 */ sw $s4, 0x28($sp)
/* 85B0 8002D1B0 3C148006 */ lui $s4, %hi(osEPiReadIo)
/* 85B4 8002D1B4 26940DC0 */ addiu $s4, $s4, %lo(osEPiReadIo)
/* 85B8 8002D1B8 AFBF003C */ sw $ra, 0x3c($sp)
/* 85BC 8002D1BC AFBE0038 */ sw $fp, 0x38($sp)
/* 85C0 8002D1C0 AFB70034 */ sw $s7, 0x34($sp)
/* 85C4 8002D1C4 0280F809 */ jalr $s4
/* 85C8 8002D1C8 AFB1001C */ sw $s1, 0x1c($sp)
/* 85CC 8002D1CC 3C110031 */ lui $s1, 0x31
/* 85D0 8002D1D0 26316D90 */ addiu $s1, $s1, 0x6d90
/* 85D4 8002D1D4 8FA20010 */ lw $v0, 0x10($sp)
/* 85D8 8002D1D8 3C030031 */ lui $v1, 0x31
/* 85DC 8002D1DC 24636F30 */ addiu $v1, $v1, 0x6f30
/* 85E0 8002D1E0 02629823 */ subu $s3, $s3, $v0
/* 85E4 8002D1E4 0223102B */ sltu $v0, $s1, $v1
/* 85E8 8002D1E8 1040002B */ beqz $v0, .L8002D298
/* 85EC 8002D1EC 241E0003 */ addiu $fp, $zero, 3
/* 85F0 8002D1F0 0060B82D */ daddu $s7, $v1, $zero
.L8002D1F4:
/* 85F4 8002D1F4 0220282D */ daddu $a1, $s1, $zero
/* 85F8 8002D1F8 3C04800A */ lui $a0, %hi(nuPiCartHandle)
/* 85FC 8002D1FC 8C84A638 */ lw $a0, %lo(nuPiCartHandle)($a0)
/* 8600 8002D200 0280F809 */ jalr $s4
/* 8604 8002D204 27A60010 */ addiu $a2, $sp, 0x10
/* 8608 8002D208 8FA30010 */ lw $v1, 0x10($sp)
/* 860C 8002D20C 2407000F */ addiu $a3, $zero, 0xf
/* 8610 8002D210 3065FFFF */ andi $a1, $v1, 0xffff
/* 8614 8002D214 00032402 */ srl $a0, $v1, 0x10
/* 8618 8002D218 00A41021 */ addu $v0, $a1, $a0
/* 861C 8002D21C 02028021 */ addu $s0, $s0, $v0
/* 8620 8002D220 00121682 */ srl $v0, $s2, 0x1a
/* 8624 8002D224 14470010 */ bne $v0, $a3, .L8002D268
/* 8628 8002D228 00031682 */ srl $v0, $v1, 0x1a
/* 862C 8002D22C 24070009 */ addiu $a3, $zero, 9
/* 8630 8002D230 50470004 */ beql $v0, $a3, .L8002D244
/* 8634 8002D234 00031542 */ srl $v0, $v1, 0x15
/* 8638 8002D238 24070023 */ addiu $a3, $zero, 0x23
/* 863C 8002D23C 1447000A */ bne $v0, $a3, .L8002D268
/* 8640 8002D240 00031542 */ srl $v0, $v1, 0x15
.L8002D244:
/* 8644 8002D244 3043001F */ andi $v1, $v0, 0x1f
/* 8648 8002D248 00121402 */ srl $v0, $s2, 0x10
/* 864C 8002D24C 3042001F */ andi $v0, $v0, 0x1f
/* 8650 8002D250 14620005 */ bne $v1, $v0, .L8002D268
/* 8654 8002D254 3082001F */ andi $v0, $a0, 0x1f
/* 8658 8002D258 14620003 */ bne $v1, $v0, .L8002D268
/* 865C 8002D25C 3242FFFF */ andi $v0, $s2, 0xffff
/* 8660 8002D260 02058023 */ subu $s0, $s0, $a1
/* 8664 8002D264 02028023 */ subu $s0, $s0, $v0
.L8002D268:
/* 8668 8002D268 8FA40010 */ lw $a0, 0x10($sp)
/* 866C 8002D26C 00041682 */ srl $v0, $a0, 0x1a
/* 8670 8002D270 145E0006 */ bne $v0, $fp, .L8002D28C
/* 8674 8002D274 26310004 */ addiu $s1, $s1, 4
/* 8678 8002D278 3083FFFF */ andi $v1, $a0, 0xffff
/* 867C 8002D27C 00041402 */ srl $v0, $a0, 0x10
/* 8680 8002D280 3042FC00 */ andi $v0, $v0, 0xfc00
/* 8684 8002D284 00621821 */ addu $v1, $v1, $v0
/* 8688 8002D288 02038023 */ subu $s0, $s0, $v1
.L8002D28C:
/* 868C 8002D28C 0237102B */ sltu $v0, $s1, $s7
/* 8690 8002D290 1440FFD8 */ bnez $v0, .L8002D1F4
/* 8694 8002D294 0080902D */ daddu $s2, $a0, $zero
.L8002D298:
/* 8698 8002D298 3C02FFD5 */ lui $v0, 0xffd5
/* 869C 8002D29C 3442B14A */ ori $v0, $v0, 0xb14a
/* 86A0 8002D2A0 02021021 */ addu $v0, $s0, $v0
/* 86A4 8002D2A4 02621023 */ subu $v0, $s3, $v0
/* 86A8 8002D2A8 02C2B021 */ addu $s6, $s6, $v0
/* 86AC 8002D2AC 3C1318F4 */ lui $s3, 0x18f4
/* 86B0 8002D2B0 367314AB */ ori $s3, $s3, 0x14ab
/* 86B4 8002D2B4 0000802D */ daddu $s0, $zero, $zero
/* 86B8 8002D2B8 3C05B000 */ lui $a1, 0xb000
/* 86BC 8002D2BC 34A50E38 */ ori $a1, $a1, 0xe38
/* 86C0 8002D2C0 27A60014 */ addiu $a2, $sp, 0x14
/* 86C4 8002D2C4 3C04800A */ lui $a0, %hi(nuPiCartHandle)
/* 86C8 8002D2C8 8C84A638 */ lw $a0, %lo(nuPiCartHandle)($a0)
/* 86CC 8002D2CC 3C148006 */ lui $s4, %hi(osEPiReadIo)
/* 86D0 8002D2D0 26940DC0 */ addiu $s4, $s4, %lo(osEPiReadIo)
/* 86D4 8002D2D4 0280F809 */ jalr $s4
/* 86D8 8002D2D8 0200902D */ daddu $s2, $s0, $zero
/* 86DC 8002D2DC 3C110031 */ lui $s1, 0x31
/* 86E0 8002D2E0 26316F30 */ addiu $s1, $s1, 0x6f30
/* 86E4 8002D2E4 8FA20014 */ lw $v0, 0x14($sp)
/* 86E8 8002D2E8 3C030031 */ lui $v1, 0x31
/* 86EC 8002D2EC 24637020 */ addiu $v1, $v1, 0x7020
/* 86F0 8002D2F0 02629823 */ subu $s3, $s3, $v0
/* 86F4 8002D2F4 0223102B */ sltu $v0, $s1, $v1
/* 86F8 8002D2F8 1040002B */ beqz $v0, .L8002D3A8
/* 86FC 8002D2FC 241E0003 */ addiu $fp, $zero, 3
/* 8700 8002D300 0060B82D */ daddu $s7, $v1, $zero
.L8002D304:
/* 8704 8002D304 0220282D */ daddu $a1, $s1, $zero
/* 8708 8002D308 3C04800A */ lui $a0, %hi(nuPiCartHandle)
/* 870C 8002D30C 8C84A638 */ lw $a0, %lo(nuPiCartHandle)($a0)
/* 8710 8002D310 0280F809 */ jalr $s4
/* 8714 8002D314 27A60014 */ addiu $a2, $sp, 0x14
/* 8718 8002D318 8FA30014 */ lw $v1, 0x14($sp)
/* 871C 8002D31C 2407000F */ addiu $a3, $zero, 0xf
/* 8720 8002D320 3065FFFF */ andi $a1, $v1, 0xffff
/* 8724 8002D324 00032402 */ srl $a0, $v1, 0x10
/* 8728 8002D328 00A41021 */ addu $v0, $a1, $a0
/* 872C 8002D32C 02028021 */ addu $s0, $s0, $v0
/* 8730 8002D330 00121682 */ srl $v0, $s2, 0x1a
/* 8734 8002D334 14470010 */ bne $v0, $a3, .L8002D378
/* 8738 8002D338 00031682 */ srl $v0, $v1, 0x1a
/* 873C 8002D33C 24070009 */ addiu $a3, $zero, 9
/* 8740 8002D340 50470004 */ beql $v0, $a3, .L8002D354
/* 8744 8002D344 00031542 */ srl $v0, $v1, 0x15
/* 8748 8002D348 24070023 */ addiu $a3, $zero, 0x23
/* 874C 8002D34C 1447000A */ bne $v0, $a3, .L8002D378
/* 8750 8002D350 00031542 */ srl $v0, $v1, 0x15
.L8002D354:
/* 8754 8002D354 3043001F */ andi $v1, $v0, 0x1f
/* 8758 8002D358 00121402 */ srl $v0, $s2, 0x10
/* 875C 8002D35C 3042001F */ andi $v0, $v0, 0x1f
/* 8760 8002D360 14620005 */ bne $v1, $v0, .L8002D378
/* 8764 8002D364 3082001F */ andi $v0, $a0, 0x1f
/* 8768 8002D368 14620003 */ bne $v1, $v0, .L8002D378
/* 876C 8002D36C 3242FFFF */ andi $v0, $s2, 0xffff
/* 8770 8002D370 02058023 */ subu $s0, $s0, $a1
/* 8774 8002D374 02028023 */ subu $s0, $s0, $v0
.L8002D378:
/* 8778 8002D378 8FA40014 */ lw $a0, 0x14($sp)
/* 877C 8002D37C 00041682 */ srl $v0, $a0, 0x1a
/* 8780 8002D380 145E0006 */ bne $v0, $fp, .L8002D39C
/* 8784 8002D384 26310004 */ addiu $s1, $s1, 4
/* 8788 8002D388 3083FFFF */ andi $v1, $a0, 0xffff
/* 878C 8002D38C 00041402 */ srl $v0, $a0, 0x10
/* 8790 8002D390 3042FC00 */ andi $v0, $v0, 0xfc00
/* 8794 8002D394 00621821 */ addu $v1, $v1, $v0
/* 8798 8002D398 02038023 */ subu $s0, $s0, $v1
.L8002D39C:
/* 879C 8002D39C 0237102B */ sltu $v0, $s1, $s7
/* 87A0 8002D3A0 1440FFD8 */ bnez $v0, .L8002D304
/* 87A4 8002D3A4 0080902D */ daddu $s2, $a0, $zero
.L8002D3A8:
/* 87A8 8002D3A8 3C04FFF1 */ lui $a0, 0xfff1
/* 87AC 8002D3AC 34842BE4 */ ori $a0, $a0, 0x2be4
/* 87B0 8002D3B0 02042021 */ addu $a0, $s0, $a0
/* 87B4 8002D3B4 02642023 */ subu $a0, $s3, $a0
/* 87B8 8002D3B8 02A42021 */ addu $a0, $s5, $a0
/* 87BC 8002D3BC 3C050031 */ lui $a1, 0x31
/* 87C0 8002D3C0 24A57020 */ addiu $a1, $a1, 0x7020
/* 87C4 8002D3C4 0C00A5CF */ jal dma_copy
/* 87C8 8002D3C8 02C0302D */ daddu $a2, $s6, $zero
/* 87CC 8002D3CC 8FBF003C */ lw $ra, 0x3c($sp)
/* 87D0 8002D3D0 8FBE0038 */ lw $fp, 0x38($sp)
/* 87D4 8002D3D4 8FB70034 */ lw $s7, 0x34($sp)
/* 87D8 8002D3D8 8FB60030 */ lw $s6, 0x30($sp)
/* 87DC 8002D3DC 8FB5002C */ lw $s5, 0x2c($sp)
/* 87E0 8002D3E0 8FB40028 */ lw $s4, 0x28($sp)
/* 87E4 8002D3E4 8FB30024 */ lw $s3, 0x24($sp)
/* 87E8 8002D3E8 8FB20020 */ lw $s2, 0x20($sp)
/* 87EC 8002D3EC 8FB1001C */ lw $s1, 0x1c($sp)
/* 87F0 8002D3F0 8FB00018 */ lw $s0, 0x18($sp)
/* 87F4 8002D3F4 03E00008 */ jr $ra
/* 87F8 8002D3F8 27BD0040 */ addiu $sp, $sp, 0x40
/* 87FC 8002D3FC 00000000 */ nop

View File

@ -7,7 +7,8 @@ options:
mnemonic_ljust: 10
platform: n64
subalign: 8
auto_all_sections: True
auto_all_sections: [".data", ".rodata", ".bss"]
asm_data_macro: "dlabel"
base_path: ../..
target_path: ver/us/baserom.z64
@ -37,7 +38,8 @@ segments:
subsegments:
- [0x0040, asm, boot]
- [0x0B70, bin, rspboot_font]
- type: code
- name: main
type: code
start: 0x1000
vram: 0x80025C00
subsegments:
@ -286,7 +288,6 @@ segments:
type: .data
name: curtains
subsegments:
- [0x4F9E0, .data, curtains]
- [0x4F9E0, i4, sprite/unk_checkers, 16, 32]
- [0x4FAE0]
- [0x4FB30, rgba32, sprite/curtains, 32, 32]
@ -758,7 +759,7 @@ segments:
type: .data
name: 8e790_len_2850
subsegments:
- [0xA2D90, .data, 8e790_len_2850]
- [0xA2D90]
- [0xA2E90, ia8, ui/box/corners9, 16, 64]
- [0xA3290, ia8, ui/box/corners8, 24, 96]
- [0xA3B90, ia8, ui/box/corners6, 16, 40]
@ -805,7 +806,7 @@ segments:
type: .data
name: cd180_len_38f0
subsegments:
- [0xE2DF0, .data, cd180_len_38f0]
- [0xE2DF0]
- [0xE2E00, i4, ui/stencil/star, 32, 64]
- [0xE3200, i4, ui/stencil/mario, 64, 64]
- [0xE3A00, i4, ui/stencil/sharp_circle, 32, 32]
@ -1111,7 +1112,8 @@ segments:
- [0x161E70, .data, pause_gfx]
- [0x162D30, .data, pause_styles]
- [0x1632A0]
- type: code
- name: filemenu
type: code
start: 0x163400
vram: 0x80242BA0
subsegments:
@ -2494,7 +2496,42 @@ segments:
- [0x325AD0, c]
- [0x325EE0, pm_effect_shims, effect_shims]
- [0x326160, .data, 325AD0]
- [0x326410, bin] # big_smoke_puff gfx
- name: effect_gfx_big_smoke_puff
dir: effects/gfx
type: code
start: 0x326410
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x326410, c, big_smoke_puff]
- start: 0x326410
type: .data
name: big_smoke_puff
subsegments:
- [0x326410, ci4, D_09000000_326410, 32, 32]
- [0x326610, palette, D_09000000_326410]
- [0x326630, ci4, D_09000220_326630, 32, 32]
- [0x326830, palette, D_09000220_326630]
- [0x326850, ci4, D_09000440_326850, 32, 32]
- [0x326A50, palette, D_09000440_326850]
- [0x326A70, ci4, D_09000660_326A70, 32, 32]
- [0x326C70, palette, D_09000660_326A70]
- [0x326C90, ci4, D_09000880_326C90, 32, 32]
- [0x326E90, palette, D_09000880_326C90]
- [0x326EB0, ci4, D_09000AA0_326EB0, 32, 32]
- [0x3270B0, palette, D_09000AA0_326EB0]
- [0x3270D0, ci4, D_09000CC0_3270D0, 32, 32]
- [0x3272D0, palette, D_09000CC0_3270D0]
- [0x3272F0, vtx, D_09000EE0_3272F0]
- [0x327330, gfx, D_09000F20_327330]
- [0x327398, gfx, D_09000F88_327398]
- [0x3273B0, gfx, D_09000FA0_3273B0]
- [0x327470, gfx, D_09001060_327470]
- [0x327530, gfx, D_09001120_327530]
- [0x3275F0, gfx, D_090011E0_3275F0]
- [0x3276B0, gfx, D_090012A0_3276B0]
- [0x327770, gfx, D_09001360_327770]
- [0x327830, gfx, D_09001420_327830]
- name: effect_big_smoke_puff
dir: effects
type: code
@ -2528,7 +2565,37 @@ segments:
subsegments:
- [0x32C7A0, c, flower_splash]
- [0x32CEB0]
- [0x32CEC0, bin] # flower_splash, flower_trail gfx
- name: effect_gfx_flower_splash_trail
dir: effects/gfx
type: code
start: 0x32CEC0
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x32CEC0, c, flower_splash_trail]
- start: 0x32CEC0
type: .data
name: flower_splash_trail
subsegments:
- [0x32CEC0, ci4, D_09000000_32CEC0, 16, 16]
- [0x32CF40, palette, D_09000000_32CEC0]
- [0x32CF60, palette, D_09000000_32CEC0.yellow]
- [0x32CF80, rgba16, D_090000C0_32CF80, 32, 32]
- [0x32D780, vtx, D_090008C0_32D780]
- [0x32D8F0, vtx, D_09000A30_32D8F0]
- [0x32D900, vtx, D_09000A40_32D900]
- [0x32D910, vtx, D_09000A50_32D910]
- [0x32D950, vtx, D_09000A90_32D950]
- [0x32D970, vtx, D_09000AB0_32D970]
- [0x32D9B0, vtx, D_09000AF0_32D9B0]
- [0x32DA10, gfx, D_09000B50_32DA10]
- [0x32DAD0, gfx, D_09000C10_32DAD0]
- [0x32DB90, gfx, D_09000CD0_32DB90]
- [0x32DC18, gfx, D_09000D58_32DC18]
- [0x32DC50, gfx, D_09000D90_32DC50]
- [0x32DCC8, gfx, D_09000E08_32DCC8]
- [0x32DCE0, gfx, D_09000E20_32DCE0]
- [0x32DCF8, gfx, D_09000E38_32DCF8]
- name: effect_flower_trail
dir: effects
type: code
@ -2544,7 +2611,24 @@ segments:
subsegments:
- [0x32E490, c, cloud_puff]
- [0x32EC10]
- [0x32EC50, bin] # cloud_puff, cloud_trail gfx
- name: effect_gfx_cloud_puff_trail
dir: effects/gfx
type: code
start: 0x32EC50
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x32EC50, c, cloud_puff_trail]
- start: 0x32EC50
type: .data
name: cloud_puff_trail
subsegments:
- [0x32EC50, ci4, D_09000000_32EC50, 16, 16]
- [0x32ECD0, palette, D_09000000_32EC50]
- [0x32ECF0, vtx, D_090000A0_32ECF0]
- [0x32ED30, gfx, D_090000E0_32ED30]
- [0x32EE08, gfx, D_090001B8_32EE08]
- [0x32EE28]
- name: effect_cloud_trail
dir: effects
type: code
@ -2560,7 +2644,22 @@ segments:
vram: 0xE0018000
subsegments:
- [0x32F580, c, footprint]
- [0x32FB50, bin] # footprint gfx
- name: effect_gfx_footprint
dir: effects/gfx
type: code
start: 0x32FB50
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x32FB50, c, footprint]
- start: 0x32FB50
type: .data
name: footprint
subsegments:
- [0x32FB50, i4, D_09000000_32FB50, 32, 32]
- [0x32FD50, vtx, D_09000200_32FD50]
- [0x32FD90, gfx, D_09000240_32FD90]
- [0x32FE28]
- name: effect_floating_flower
dir: effects
type: code
@ -2569,7 +2668,26 @@ segments:
subsegments:
- [0x32FE30, c, floating_flower]
- [0x330440]
- [0x330460, bin] # floating_flower gfx
- name: effect_gfx_floating_flower
dir: effects/gfx
type: code
start: 0x330460
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x330460, c, floating_flower]
- start: 0x330460
type: .data
name: floating_flower
subsegments:
- [0x330460, ci4, D_09000000_330460, 16, 16]
- [0x3304E0, palette, D_09000000_330460]
- [0x330500, vtx, D_090000A0_330500]
- [0x3305D0, vtx, D_09000170_3305D0]
- [0x330690, vtx, D_09000230_330690]
- [0x330750, gfx, D_090002F0_330750]
- [0x3308B0, gfx, D_09000450_3308B0]
- [0x330908]
- name: effect_snowflake
dir: effects
type: code
@ -2578,7 +2696,26 @@ segments:
subsegments:
- [0x330910, c, snowflake]
- [0x330EF0]
- [0x330F00, bin] # snowflake gfx
- name: effect_gfx_snowflake
dir: effects/gfx
type: code
start: 0x330F00
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x330F00, c, snowflake]
- start: 0x330F00
type: .data
name: snowflake
subsegments:
- [0x330F00, i4, D_09000000_330F00, 16, 16]
- [0x330F80, i4, D_09000080_330F80, 64, 64]
- [0x331780, vtx, D_09000880_331780]
- [0x3317C0, vtx, D_090008C0_3317C0]
- [0x331800, gfx, D_09000900_331800]
- [0x3318E8, gfx, D_090009E8_3318E8]
- [0x331910, gfx, D_09000A10_331910]
- [0x331938]
- name: effect_star
dir: effects
type: code
@ -2721,7 +2858,62 @@ segments:
- [0x34F4C0, c, damage_indicator]
- [0x350160, .data, damage_indicator]
- [0x350200, .rodata, damage_indicator]
- [0x350220, bin] # damage_indicator gfx
- name: effect_gfx_damage_indicator
dir: effects/gfx
type: code
start: 0x350220
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x350220, c, damage_indicator]
- start: 0x350220
type: .data
name: damage_indicator
subsegments:
- [0x350220, i4, D_09000000_350220, 32, 32]
- [0x350420, i4, D_09000200_350420, 32, 32]
- [0x350620, i4, D_09000400_350620, 32, 32]
- [0x350820, i4, D_09000600_350820, 32, 32]
- [0x350A20, i4, D_09000800_350A20, 32, 32]
- [0x350C20, i4, D_09000A00_350C20, 32, 32]
- [0x350E20, i4, D_09000C00_350E20, 32, 32]
- [0x351020, i4, D_09000E00_351020, 32, 32]
- [0x351220, i4, D_09001000_351220, 32, 32]
- [0x351420, i4, D_09001200_351420, 32, 32]
- [0x351620, i4, D_09001400_351620, 32, 32]
- [0x351820, i4, D_09001600_351820, 32, 32]
- [0x351A20, i4, D_09001800_351A20, 32, 32]
- [0x351C20, i4, D_09001A00_351C20, 32, 32]
- [0x351E20, vtx, D_09001C00_351E20]
- [0x351E30, vtx, D_09001C10_351E30]
- [0x351E50, vtx, D_09001C30_351E50]
- [0x351E60, vtx, D_09001C40_351E60]
- [0x351EA0, vtx, D_09001C80_351EA0]
- [0x351EE0, vtx, D_09001CC0_351EE0]
- [0x351F20, vtx, D_09001D00_351F20]
- [0x351F60, gfx, D_09001D40_351F60]
- [0x352000, gfx, D_09001DE0_352000]
- [0x352070, gfx, D_09001E50_352070]
- [0x3520B0, gfx, D_09001E90_3520B0]
- [0x3520F0, gfx, D_09001ED0_3520F0]
- [0x352130, gfx, D_09001F10_352130]
- [0x352170, gfx, D_09001F50_352170]
- [0x3521B0, gfx, D_09001F90_3521B0]
- [0x3521F0, gfx, D_09001FD0_3521F0]
- [0x352230, gfx, D_09002010_352230]
- [0x352270, gfx, D_09002050_352270]
- [0x3522B0, gfx, D_09002090_3522B0]
- [0x3522F0, gfx, D_090020D0_3522F0]
- [0x352330, gfx, D_09002110_352330]
- [0x352370, gfx, D_09002150_352370]
- [0x352380, gfx, D_09002160_352380]
- [0x352390, gfx, D_09002170_352390]
- [0x3523A0, gfx, D_09002180_3523A0]
- [0x3523B0, gfx, D_09002190_3523B0]
- [0x3523C8, gfx, D_090021A8_3523C8]
- [0x3523E0, gfx, D_090021C0_3523E0]
- [0x352400, gfx, D_090021E0_352400]
- [0x352420, gfx, D_09002200_352420]
- name: effect_purple_ring
dir: effects
type: code
@ -2870,7 +3062,26 @@ segments:
subsegments:
- [0x363160, c, big_snowflakes]
- [0x363890]
- [0x3638C0, bin] # big_snowflakes gfx
- name: effect_gfx_big_snowflakes
dir: effects/gfx
type: code
start: 0x3638C0
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x3638C0, c, big_snowflakes]
- start: 0x3638C0
type: .data
name: big_snowflakes
subsegments:
- [0x3638C0, i4, D_09000000_3638C0, 16, 16]
- [0x363940, i4, D_09000080_363940, 64, 64]
- [0x364140, vtx, D_09000880_364140]
- [0x364180, vtx, D_090008C0_364180]
- [0x3641C0, gfx, D_09000900_3641C0]
- [0x3642A8, gfx, D_090009E8_3642A8]
- [0x3642D0, gfx, D_09000A10_3642D0]
- [0x3642F8]
- name: effect_debuff
dir: effects
type: code
@ -2879,7 +3090,23 @@ segments:
subsegments:
- [0x364300, c, debuff]
- [0x364BC0]
- [0x364C00, bin] # debuff gfx
- name: effect_gfx_debuff
dir: effects/gfx
type: code
start: 0x364C00
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x364C00, c, debuff]
- start: 0x364C00
type: .data
name: debuff
subsegments:
- [0x364C00, i4, D_09000000_364C00, 32, 32]
- [0x364E00, vtx, D_09000200_364E00]
- [0x364E40, gfx, D_09000240_364E40]
- [0x364EE8, gfx, D_090002E8_364EE8]
- [0x364F08]
- name: effect_green_impact
dir: effects
type: code
@ -3021,7 +3248,54 @@ segments:
subsegments:
- [0x385640, c, disable_x]
- [0x386340]
- [0x3863B0, bin] # disable_x gfx
- name: effect_gfx_disable_x
dir: effects/gfx
type: code
start: 0x3863B0
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x3863B0, c, disable_x]
- start: 0x3863B0
type: .data
name: disable_x
subsegments:
- [0x3863B0, i4, D_09000000_3863B0, 32, 32]
- [0x3865B0, i4, D_09000200_3865B0, 32, 32]
- [0x3867B0, i4, D_09000400_3867B0, 32, 32]
- [0x3869B0, i4, D_09000600_3869B0, 32, 32]
- [0x386BB0, i4, D_09000800_386BB0, 32, 32]
- [0x386DB0, i4, D_09000A00_386DB0, 32, 32]
- [0x386FB0, i4, D_09000C00_386FB0, 32, 32]
- [0x3871B0, i4, D_09000E00_3871B0, 32, 32]
- [0x3873B0, i4, D_09001000_3873B0, 32, 32]
- [0x3875B0, i4, D_09001200_3875B0, 32, 32]
- [0x3877B0, i4, D_09001400_3877B0, 32, 32]
- [0x3879B0, i4, D_09001600_3879B0, 32, 32]
- [0x387BB0, rgba16, D_09001800_387BB0, 32, 32]
- [0x3883B0, vtx, D_09002000_3883B0]
- [0x3883F0, vtx, D_09002040_3883F0]
- [0x388430, vtx, D_09002080_388430]
- [0x388470, vtx, D_090020C0_388470]
- [0x3884B0, gfx, D_09002100_3884B0]
- [0x388548, gfx, D_09002198_388548]
- [0x3885E0, gfx, D_09002230_3885E0]
- [0x388600, gfx, D_09002250_388600]
- [0x388620, gfx, D_09002270_388620]
- [0x388640, gfx, D_09002290_388640]
- [0x388660, gfx, D_090022B0_388660]
- [0x3886D0, gfx, D_09002320_3886D0]
- [0x388710, gfx, D_09002360_388710]
- [0x388750, gfx, D_090023A0_388750]
- [0x388790, gfx, D_090023E0_388790]
- [0x3887D0, gfx, D_09002420_3887D0]
- [0x388810, gfx, D_09002460_388810]
- [0x388850, gfx, D_090024A0_388850]
- [0x388890, gfx, D_090024E0_388890]
- [0x3888D0, gfx, D_09002520_3888D0]
- [0x388910, gfx, D_09002560_388910]
- [0x388950, gfx, D_090025A0_388950]
- [0x388990, gfx, D_090025E0_388990]
- name: effect_bombette_breaking
dir: effects
type: code
@ -3100,7 +3374,31 @@ segments:
subsegments:
- [0x391D30, c, small_gold_sparkle]
- [0x3923C0]
- [0x392440, bin] # small_gold_sparkle gfx
- name: effect_gfx_small_gold_sparkle
dir: effects/gfx
type: code
start: 0x392440
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x392440, c, small_gold_sparkle]
- start: 0x392440
type: .data
name: small_gold_sparkle
subsegments:
- [0x392440, i4, D_09000000_392440, 16, 16]
- [0x3924C0, i4, D_09000080_3924C0, 16, 16]
- [0x392540, i4, D_09000100_392540, 16, 16]
- [0x3925C0, i4, D_09000180_3925C0, 16, 16]
- [0x392640, i4, D_09000200_392640, 16, 16]
- [0x3926C0, vtx, D_09000280_3926C0]
- [0x392700, gfx, D_090002C0_392700]
- [0x392770, gfx, D_09000330_392770]
- [0x3927B0, gfx, D_09000370_3927B0]
- [0x3927F0, gfx, D_090003B0_3927F0]
- [0x392830, gfx, D_090003F0_392830]
- [0x392870, gfx, D_09000430_392870]
- [0x3928B0, gfx, D_09000470_3928B0]
- name: effect_flashing_box_shockwave
dir: effects
type: code
@ -3205,7 +3503,55 @@ segments:
subsegments:
- [0x3AA920, c, butterflies]
- [0x3AAFE0]
- [0x3AB030, bin] # butterflies gfx
- name: effect_gfx_butterflies
dir: effects/gfx
type: code
start: 0x3AB030
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x3AB030, c, butterflies]
- start: 0x3AB030
type: .data
name: butterflies
subsegments:
- [0x3AB030, ci4, D_09000000_3AB030, 32, 64]
- [0x3AB430, palette, D_09000000_3AB030]
- [0x3AB450, ci4, D_09000420_3AB450, 32, 64]
- [0x3AB850, palette, D_09000420_3AB450]
- [0x3AB870, ci4, D_09000840_3AB870, 32, 64]
- [0x3ABC70, palette, D_09000840_3AB870]
- [0x3ABC80, ci4, D_09000C50_3ABC80, 32, 64]
- [0x3AC080, palette, D_09000C50_3ABC80]
- [0x3AC0A0, ci4, D_09001070_3AC0A0, 32, 64]
- [0x3AC4A0, palette, D_09001070_3AC0A0]
- [0x3AC4B0, ci4, D_09001480_3AC4B0, 32, 64]
- [0x3AC8B0, palette, D_09001480_3AC4B0]
- [0x3AC8D0, ci4, D_090018A0_3AC8D0, 32, 64]
- [0x3ACCD0, palette, D_090018A0_3AC8D0]
- [0x3ACCF0, ci4, D_09001CC0_3ACCF0, 32, 64]
- [0x3AD0F0, palette, D_09001CC0_3ACCF0]
- [0x3AD110, ci4, D_090020E0_3AD110, 32, 64]
- [0x3AD510, palette, D_090020E0_3AD110]
- [0x3AD530, ci4, D_09002500_3AD530, 32, 64]
- [0x3AD930, palette, D_09002500_3AD530]
- [0x3AD950, ci4, D_09002920_3AD950, 32, 64]
- [0x3ADD50, palette, D_09002920_3AD950]
- [0x3ADD70, vtx, D_09002D40_3ADD70]
- [0x3AE8B0, gfx, D_09003880_3AE8B0]
- [0x3AE928, gfx, D_090038F8_3AE928]
- [0x3AE998, gfx, D_09003968_3AE998]
- [0x3AEA08, gfx, D_090039D8_3AEA08]
- [0x3AEA78, gfx, D_09003A48_3AEA78]
- [0x3AEAE8, gfx, D_09003AB8_3AEAE8]
- [0x3AEB58, gfx, D_09003B28_3AEB58]
- [0x3AEBC8, gfx, D_09003B98_3AEBC8]
- [0x3AEC38, gfx, D_09003C08_3AEC38]
- [0x3AECA8, gfx, D_09003C78_3AECA8]
- [0x3AED18, gfx, D_09003CE8_3AED18]
- [0x3AED88, gfx, D_09003D58_3AED88]
- [0x3AEDF8, gfx, D_09003DC8_3AEDF8]
- [0x3AEE18]
- name: effect_stat_change
dir: effects
type: code
@ -3339,7 +3685,28 @@ segments:
subsegments:
- [0x3CF3A0, c, throw_spiny]
- [0x3CFAB0]
- [0x3CFAF0, bin] # throw_spiny gfx
- name: effect_gfx_throw_spiny
dir: effects/gfx
type: code
start: 0x3CFAF0
vram: 0x09000000
symbol_name_format: $VRAM_$ROM
subsegments:
- [0x3CFAF0, c, throw_spiny]
- start: 0x3CFAF0
type: .data
name: throw_spiny
subsegments:
- [0x3CFAF0, ci4, D_09000000_3CFAF0, 32, 32]
- [0x3CFCF0, palette, D_09000000_3CFAF0]
- [0x3CFD10] # padding
- [0x3CFEF0, ci4, D_09000400_3CFEF0, 32, 32]
- [0x3D00F0, palette, D_09000400_3CFEF0]
- [0x3D0110] # padding
- [0x3D02F0, gfx, D_09000800_3D02F0]
- [0x3D03C8, gfx, D_090008D8_3D03C8]
- [0x3D04A0, vtx, D_090009B0_3D04A0]
- [0x3D04E0, gfx, D_090009F0_3D04E0]
- name: effect_effect_65
dir: effects
type: code
@ -3808,7 +4175,6 @@ segments:
type: .data
name: whirlwind
subsegments:
- [0x424550, .data, whirlwind]
- [0x424550, ci4, whirlwind_1, 24, 24]
- [0x424670, palette, whirlwind_1]
- [0x424690, ci4, whirlwind_2, 24, 24]
@ -3929,7 +4295,6 @@ segments:
type: .data
name: water_block
subsegments:
- [0x42B650, .data, water_block]
- [0x42B650, ci4, water_block_1, 24, 24]
- [0x42B770, palette, water_block_1]
- [0x42B790, ci4, water_block_2, 24, 24]
@ -4588,7 +4953,7 @@ segments:
type: .data
name: actor/monstar
subsegments:
- [0x63F040, .data, actor/monstar]
- [0x63F040]
- [0x63F278, ci4, actor/img, 32, 32]
- [0x63F478, palette, actor/img]
- [0x63F498]
@ -4813,7 +5178,7 @@ segments:
vram: 0x802A1000
overlay: True
subsegments:
- [0x715850, c, mushroom] # TODO fix auto_all for .data
- [0x715850, c, mushroom]
- [0x715E50]
- name: fire_flower
dir: battle/item
@ -4920,7 +5285,7 @@ segments:
type: .data
name: sleepy_sheep
subsegments:
- [0x71EFC0, .data, sleepy_sheep]
- [0x71EFC0]
- [0x71F580, ci4, sleepy_sheep1, 56, 48]
- [0x71FAC0, palette, sleepy_sheep1]
- [0x71FAE0, ci4, sleepy_sheep2, 56, 48]
@ -5030,7 +5395,7 @@ segments:
type: .data
name: egg_missile
subsegments:
- [0x7291D0, .data, egg_missile]
- [0x7291D0]
- [0x729790, ci4, egg_missile1, 32, 32]
- [0x729990, palette, egg_missile1]
- [0x7299B0, ci4, egg_missile2, 32, 32]
@ -5077,7 +5442,7 @@ segments:
type: .data
name: mystery
subsegments:
- [0x72CF00, .data, mystery]
- [0x72CF00]
- [0x72D4C0, ci4, mystery, 32, 32]
- [0x72D6C0, palette, mystery]
- [0x72D6E0]
@ -5111,7 +5476,7 @@ segments:
type: .data
name: coconut
subsegments:
- [0x72F960, .data, coconut]
- [0x72F960]
- [0x72FF20, ci4, coconut, 32, 32]
- [0x730120, palette, coconut]
- [0x730140]
@ -5136,7 +5501,7 @@ segments:
type: .data
name: strange_cake
subsegments:
- [0x731EA0, .data, strange_cake]
- [0x731EA0]
- [0x732470, ci4, strange_cake1, 32, 32]
- [0x732670, palette, strange_cake1]
- [0x732690, ci4, strange_cake2, 32, 32]
@ -7002,7 +7367,7 @@ segments:
type: .data
name: 9694C0
subsegments:
- [0x96CC30, .data, 9694C0]
- [0x96CC30]
- [0x971F98, vtx, vtx/971F98]
- [0x9722B8, vtx, vtx/9722B8]
- [0x973578]

File diff suppressed because it is too large Load Diff

View File

@ -58,25 +58,18 @@ D_F79DDD0F = 0xF79DDD0F;
D_FA000028 = 0xFA000028;
D_FD100008 = 0xFD100008;
D_7599F6D8 = 0x7599F6D8;
// Obfuscation symbols
D_7012ACA1 = 0x7012ACA1;
D_7012BC11 = 0x7012BC11;
D_80026AC7 = 0x80026AC7;
D_8004AA85 = 0x8004AA85;
obfuscated_battle_heap_create = battle_heap_create - 0xFEFFFFF;
obfuscated_general_heap_create = general_heap_create - 0xFEFEFEF;
obfuscated_load_engine_data = load_engine_data - 0x315;
obfuscated_create_audio_system = create_audio_system - 0x7B;
fx_sun_undeclared = fx_sun;
D_E007EC2F = 0xE007EC2F;
// effect_1
D_09000FA0 = 0x09000FA0;
D_09001060 = 0x09001060;
D_09001120 = 0x09001120;
D_090011E0 = 0x090011E0;
D_090012A0 = 0x090012A0;
D_09001360 = 0x09001360;
D_09001420 = 0x09001420;
// effect_6
D_09002780 = 0x09002780;
D_09002868 = 0x09002868;
@ -93,27 +86,6 @@ D_09002950 = 0x09002950;
D_09002B20 = 0x09002B20;
D_09002B40 = 0x09002B40;
// effect_8
D_09000E08 = 0x09000E08;
// effect_9
D_09000E20 = 0x09000E20;
D_09000E38 = 0x09000E38;
// effect_10, effect_11
D_090000E0 = 0x090000E0;
D_090001B8 = 0x090001B8;
// effect_12
D_09000240 = 0x09000240;
// effect_13
D_090002F0 = 0x090002F0;
// effect_14
D_09000900 = 0x09000900;
D_090009E8 = 0x090009E8;
// effect_16
D_09002170 = 0x09002170;
D_09002238 = 0x09002238;
@ -126,19 +98,6 @@ D_090024A8 = 0x090024A8;
D_09002550 = 0x09002550;
D_09002578 = 0x09002578;
// effect 31 (debuff)
D_09000240 = 0x09000240;
D_090002E8 = 0x090002E8;
// effect_73
D_090002C0 = 0x090002C0;
D_09000330 = 0x09000330;
D_09000370 = 0x09000370;
D_090003B0 = 0x090003B0;
D_090003F0 = 0x090003F0;
D_09000430 = 0x09000430;
D_09000470 = 0x09000470;
// effect_75
D_09001280 = 0x09001280;
D_09001358 = 0x09001358;
@ -223,78 +182,6 @@ D_09000B88 = 0x09000B88;
D_09000C00 = 0x09000C00;
D_09000C20 = 0x09000C20;
// effect_disable_x
D_09002100 = 0x09002100;
D_09002198 = 0x09002198;
D_09002230 = 0x09002230;
D_09002250 = 0x09002250;
D_09002270 = 0x09002270;
D_09002290 = 0x09002290;
D_090022B0 = 0x090022B0;
D_09002320 = 0x09002320;
D_09002360 = 0x09002360;
D_090023A0 = 0x090023A0;
D_090023E0 = 0x090023E0;
D_09002420 = 0x09002420;
D_09002460 = 0x09002460;
D_090024A0 = 0x090024A0;
D_090024E0 = 0x090024E0;
D_09002520 = 0x09002520;
D_09002560 = 0x09002560;
D_090025A0 = 0x090025A0;
D_090025E0 = 0x090025E0;
// effect_throw_spiny
D_09000800 = 0x09000800;
D_090008D8 = 0x090008D8;
D_090009F0 = 0x090009F0;
// effect_damage_indicator
D_09001D40 = 0x09001D40;
D_09001DE0 = 0x09001DE0;
D_09001E50 = 0x09001E50;
D_09001E90 = 0x09001E90;
D_09001ED0 = 0x09001ED0;
D_09001F10 = 0x09001F10;
D_09001F50 = 0x09001F50;
D_09001F90 = 0x09001F90;
D_09001FD0 = 0x09001FD0;
D_09002010 = 0x09002010;
D_09002050 = 0x09002050;
D_09002090 = 0x09002090;
D_090020D0 = 0x090020D0;
D_09002110 = 0x09002110;
D_09002150 = 0x09002150;
D_09002160 = 0x09002160;
D_09002170 = 0x09002170;
D_09002180 = 0x09002180;
D_090021A8 = 0x090021A8;
D_09002190 = 0x09002190;
D_090021C0 = 0x090021C0;
D_090021E0 = 0x090021E0;
D_09002200 = 0x09002200;
// effect_big_snowflakes
D_09000900 = 0x09000900;
D_090009E8 = 0x090009E8;
D_09000A10 = 0x09000A10;
// effect_butterflies
D_09002D40 = 0x09002D40;
D_09003880 = 0x09003880;
D_090038F8 = 0x090038F8;
D_09003968 = 0x09003968;
D_090039D8 = 0x090039D8;
D_09003A48 = 0x09003A48;
D_09003AB8 = 0x09003AB8;
D_09003B28 = 0x09003B28;
D_09003B98 = 0x09003B98;
D_09003C08 = 0x09003C08;
D_09003C78 = 0x09003C78;
D_09003CE8 = 0x09003CE8;
D_09003D58 = 0x09003D58;
D_09003DC8 = 0x09003DC8;
// Invalid pointers from dead code
dead_atan2 = 0x8002AF70;
dead_gCurrentCamID = 0x800A158C;