Hack64 Wiki
Other Titles
Hack64 Wiki
Other Titles
This is an old revision of the document!
Yoshi's Story uses 32-bit “bank-offsets” to point to resources in ROM. The bank table is located at 0x000A79D4 in ROM (0x800A6DD4 in RAM) as an array of bank base addresses. There are 16 available slots for bank addresses, but only bank numbers 0x00, 0x03, and 0x04 seem to be used by the game.
Bank # | ROM address |
---|---|
0x00 | 0x00001060 |
0x01 | 0x00000000 |
0x02 | 0x00000000 |
0x03 | 0x00526EC0 |
0x04 | 0x00B47A10 |
0x05 | 0x00000000 |
0x06 | 0x00000000 |
0x07 | 0x00000000 |
0x08 | 0x00000000 |
0x09 | 0x00000000 |
0x0A | 0x00000000 |
0x0B | 0x00000000 |
0x0C | 0x00000000 |
0x0D | 0x00000000 |
0x0E | 0x00000000 |
0x0F | 0x00000000 |
Bank-offsets are 32 bits, containing a 4-bit bank number and a 24-bit offset:
---- bbbb oooooooooooooooooooooooo
Bitfield | Description |
---|---|
- | unused bits |
b | 4-bit bank number |
o | 24-bit offset |
So a bank-offset to ROM address conversion formula could look something like this:
u32 boToAddress(u32 bankOffset) { u8 bankNum = (bankOffset >> 24) & 0x0F; u32 offset = bankOffset & 0x00FFFFFF; u32 romAddress = gRomBanks[bankNum] + offset; return romAddress; }
The main level list is at 0x000A84A0 in ROM as an array of 177 “LevelEntry” structs.
This struct simply points to a LevelInfo struct.
struct LevelEntry { /*00*/ u32 unk00; /*04*/ u32 boLevelInfo; // bank-offset of LevelInfo struct };
This struct contains a pointer to an ObjectPlacementListInfo struct. The rest of the data hasn't been studied yet.
struct LevelInfo { /*00*/ u8 unk00[8]; /*08*/ f32 unk08; /*0C*/ u8 unk0C[24]; /*24*/ void *unk24; /*28*/ u8 unk28[4]; /*2C*/ f32 unk2C; /*30*/ f32 unk30; /*34*/ u8 unk34[4]; /*38*/ f32 unk38; /*3C*/ f32 unk3C; /*40*/ u8 unk40[4]; /*44*/ f32 unk44; /*48*/ f32 unk48; /*4C*/ f32 unk4C; /*50*/ u8 unk50[4]; /*54*/ f32 unk54; /*58*/ u8 unk58[4]; /*5C*/ u32 boObjectPlacementListInfoPtr; // bank-offset of bank-offset of ObjectPlacementListInfo /*60*/ u16 unk60[0x98]; // seems to be a list of objectId's to preload? terminated by 0xFFFF? unknown size /*F8*/ u8 unkF8[28]; };
This struct simply references an array of ObjectPlacement structs.
struct ObjectPlacementListInfo { /*00*/ u16 numObjects; // number of ObjectPlacement structs in the array /*02*/ u16 unk02; // probably padding /*04*/ u32 boObjectPlacements; // bank-offset of ObjectPlacement array };
This struct contains the object ID, tag(?), and position of an object to be placed in a level.
struct ObjectPlacement { u16 objectId; // object ID u16 layer; // seems to be the drawing layer, collision is active on layer 0x0001 f32 x; // x coordinate in level f32 y; // y coordinate in level };
The object lookup table is at 0x000A1C90 in ROM as an array of 1582 ObjectEntry structs.
struct ObjectEntry { /*00*/ u16 objectId; // unique identifier /*02*/ u16 unk02; // probably padding /*04*/ u32 boObjectDefA; // bank-offset of ObjectDefA struct /*08*/ u32 boObjectDefB; // bank-offset of ObjectDefB struct };
This structure defines the properties of an object.
struct ObjectDefA_00 { /*00*/ u16 type; // structure type (0x0001) u8 _pad02[2]; /*04*/ CodeInfo codeInfo; /*18*/ u16 objectId; // unique identifier /*1A*/ u16 unk1A; /*1C*/ u32 tileDimensionsSize; // sizeof(TileDimensions) /*20*/ u32 boTileDimensions; // bank-offset of TileDimensions struct /*24*/ u32 tileDataInfoSize; // sizeof(BlockInfo) /*28*/ u32 boTileDataInfo; // bank-offset of BlockInfo struct for the tiles' 8bit color-index data /*2C*/ u32 tilePaletteInfoSize; // sizeof(BlockInfo) /*30*/ u32 boTilePaletteInfo; /* bank-offset of BlockInfo struct for the tiles' palette data palette data is a 0x200 byte array of rgba5551 (u16) colors */ /*34*/ u32 tileMapInfoSize; // sizeof(BlockInfo) /*38*/ u32 boTileMapInfo; /* bank-offset of BlockInfo struct for the tile map the tile map is a u16 array tile indeces */ /*3C*/ u32 unkData1InfoSize; // sizeof(BlockInfo) /*40*/ u32 boUnkData1; // bank-offset of BlockInfo struct for ?? /*44*/ u32 unkData2InfoSize; // sizeof(BlockInfo) /*48*/ u32 boUnkData2; // bank-offset of BlockInfo struct for ?? /*4C*/ u32 collisionMapInfoSize; // sizeof(BlockInfo) /*50*/ u32 boCollisionMapInfo; /* bank-offset of BlockInfo struct for collision data the collision map is a u16 array, parallel to the tile map array */ /*54*/ u8 unk54[16]; // unknown data };
This structure defines the properties of the Yoshi player object.
struct ObjectDefA_01 // only used for yoshi { /*0x00*/ u16 type; // structure type (0x0001) /*0x04*/ u8 unk04; /*0x08*/ u32 unk08; /*0x18*/ u16 unk18; /*0x1C*/ u8 unk1C; /*0x1D*/ u8 unk1D; /*0x20*/ u32 boUnk20; /*0x24*/ u32 boUnk24; /*0x28*/ u32 boUnk28; /*0x2C*/ u32 unk2C; /*0x30*/ u32 boUnk30; /*0x34*/ u32 unk34; /*0x38*/ u32 unk38; /*0x3C*/ u32 unk3C; /*0x40*/ u32 boUnk40; };
struct ObjectDefA_02 { /*00*/ u16 type; // structure type (0x0002) u8 _pad02[2]; CodeInfo codeInfo; };
struct ObjectDefB { // todo };
struct TileDimensions { /*0x00*/ u16 unk00; // ?? related to width /*0x02*/ u16 unk02; // ?? related to height /*0x04*/ u16 tileWidth; // width of an individual tile /*0x06*/ u16 tileHeight; // height of an individual tile /*0x08*/ u16 mapWidth; // width of the whole map (num tiles X * tileWidth) /*0x0A*/ u16 mapHeight // height of the whole map (num tiles Y * tileHeight) };
This structure references a block of data in ROM. The block of data may either be raw or SMSR00 compressed depending on the size and sizeEnc fields.
struct BlockInfo { /*0x00*/ u32 size; // decoded block size /*0x04*/ u32 sizeEnc; // encoded block size /*0x08*/ u32 boData; /* bank-offset of the data (may be a CMPR or raw) if the data is raw, both size and sizeEnc will be the same value */ };
This struct references code that an object should use. It can either reference an overlay file or a single function already in memory.
struct CodeInfo { u8 useOverlay; // 1 = use overlay, 0 = use nativeFunc u8 _pad[3]; // padding union { void *nativeFunc; // pointer to native function struct { u32 romStart; // overlay rom start address u32 romEnd; // overlay rom end address void *fakeMemStart; // fake ram start address void *fakeMemEnd; // fake ram end address } overlay; }; };
Yoshi's Story uses overlays to save memory. The structure for overlay files is as follows:
u8 text[textSize] u8 data[dataSize] u8 rodata[rodataSize] meta { u32 textSize u32 dataSize u32 rodataSize u32 bssSize u32 numRelocations u32 relocations[numRelocations] u32 metaSize }
Relocation bitfields:
ss -- rrrr oooooooooooooooooooooooo
Bitfield | Description |
---|---|
s | Section (0 = invalid?, 1 = .text, 2 = .data, 3 = .rodata) |
- | Unused? |
r | Relocation type (4 = R_MIPS_26, 5 = R_MIPS_HI16, 6 = R_MIPS_LO16) |
o | Offset |
The dynamic linker routine is located at 0x80081430 in RAM.
func_80081430(void *overlay_block, void *meta_section);
The game keeps track of active overlays using an array of the following struct at 0x800DA840 in RAM.
struct OverlayEntry { /*00*/ void *location; // actual location in memory /*04*/ u16 objectId; // id of the object that this overlay belongs to u8 _pad[2]; /*08*/ void *fakeMemStart; // fake start address /*0C*/ void *fakeMemEnd; // fake end address };
Yoshi's Story uses an LZ77-type compression format called SMSR00 which is very similar to SM64's MIO0 format. Each SMSR00 block in ROM is preceded by a 16-byte 'CMPR' header which contains the size of the encoded block and the size of the block when it's decoded.
struct CMPRHeader { /*00*/ char cmprSignature[4]; // 'CMPR' /*04*/ u32 sizeEnc; // size of encoded data /*08*/ u32 size; // size of decoded data /*0C*/ u32 unused; // probably padding };
struct SMSRHeader { /*00*/ char smsrSignature[6]; // 'SMSR00' /*06*/ u8 unused[2]; // padding /*08*/ u32 outputSize; // size of decoded data /*0C*/ u32 dataOffset; // offset of the data section in the smsr00 block };