#pragma once #include "common.h" #include "language.h" #define GBAVC_MAGIC '.', 'C', 'A', 'A' #define AGBSAVE_MAGIC '.', 'S', 'A', 'V' #define AGBSAVE_MAX_SIZE (0x000180 * 0x200) // standard size of the NAND partition #define AGBSAVE_MAX_SSIZE (AGBSAVE_MAX_SIZE - sizeof(AgbSaveHeader)) // see: http://3dbrew.org/wiki/3DS_Virtual_Console#Footer #define GBASAVE_EEPROM_512 (512) #define GBASAVE_EEPROM_8K (8 * 1024) #define GBASAVE_SRAM_32K (32 * 1024) #define GBASAVE_FLASH_64K (64 * 1024) #define GBASAVE_FLASH_128K (128 * 1024) #define GBASAVE_SIZE(tp) \ (((tp == 0x0) || (tp == 0x1)) ? GBASAVE_EEPROM_512 : \ ((tp == 0x2) || (tp == 0x3)) ? GBASAVE_EEPROM_8K : \ ((tp >= 0x4) && (tp <= 0x9)) ? GBASAVE_FLASH_64K : \ ((tp >= 0xA) && (tp <= 0xD)) ? GBASAVE_FLASH_128K : \ (tp == 0xE) ? GBASAVE_SRAM_32K : 0); // last one means invalid #define GBASAVE_VALID(size) \ (((size) == GBASAVE_EEPROM_512) || \ ((size) == GBASAVE_EEPROM_8K) || \ ((size) == GBASAVE_SRAM_32K) || \ ((size) == GBASAVE_FLASH_64K) || \ ((size) == GBASAVE_FLASH_128K)) // see: http://3dbrew.org/wiki/3DS_Virtual_Console#Footer // still a lot of unknowns in here, also redundant stuff left out typedef struct { u8 unknown0[4]; u32 rom_size; u32 save_type; u8 unknown1[20]; u32 lcd_ghosting; u8 video_lut[0x300]; u8 unknown2[44]; u8 magic[4]; // ".CAA" u8 unknown3[12]; } PACKED_STRUCT AgbVcFooter; // see: http://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame typedef struct { u8 magic[4]; // ".SAV" u8 reserved0[0xC]; // always 0xFF u8 cmac[0x10]; u8 reserved1[0x10]; // always 0xFF u32 unknown0; // always 0x01 u32 times_saved; u64 title_id; u8 sd_cid[0x10]; u32 save_start; // always 0x200 u32 save_size; u8 reserved2[0x8]; // always 0xFF u32 unknown1; // has to do with ARM7? u32 unknown2; // has to do with ARM7? u8 reserved3[0x198]; // always 0xFF } PACKED_STRUCT AgbSaveHeader; // see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader typedef struct { u32 arm7_rom_entry; u8 logo[0x9C]; char game_title[12]; char game_code[4]; char maker_code[2]; u8 fixed; // 0x96, required! u8 unit_code; // 0x00 for current GBA u8 device_type; // 0x00 usually u8 reserved0[7]; // always 0x00 u8 software_version; // 0x00 usually u8 checksum; // header checksum, required u8 reserved[2]; // always 0x00 // stuff for multiboot not included } __attribute__((packed, aligned(16))) AgbHeader; u32 ValidateAgbSaveHeader(AgbSaveHeader* header); u32 ValidateAgbHeader(AgbHeader* agb); const char* AgbDestStr(const char* code);