94 lines
3.1 KiB
C
Raw Normal View History

#pragma once
#include "common.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://problemkaputt.de/gbatek.htm#gbacartridgeheader
#define AGB_DESTSTR(code) \
(((code)[3] == 'J') ? "Japan" : \
((code)[3] == 'E') ? "USA/English" : \
((code)[3] == 'P') ? "Europe/Elsewhere" : \
((code)[3] == 'D') ? "German" : \
((code)[3] == 'F') ? "French" : \
((code)[3] == 'I') ? "Italian" : \
((code)[3] == 'S') ? "Spanish" : "Unknown")
// 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
2019-05-08 00:18:34 +02:00
} __attribute__((packed, aligned(16))) AgbHeader;
u32 ValidateAgbSaveHeader(AgbSaveHeader* header);
u32 ValidateAgbHeader(AgbHeader* agb);