Added optional INFO block
This commit is contained in:
parent
2078c2a8fb
commit
f0a6488546
17
BESS.md
17
BESS.md
@ -37,14 +37,23 @@ The NAME block uses the `'NAME'` identifier, and is an optional block that conta
|
||||
The length of the NAME block is variable, and it only contains the name and version of the originating emulator in ASCII.
|
||||
|
||||
|
||||
#### INFO block
|
||||
|
||||
The INFO block uses the `'INFO'` identifier, and is an optional block that contains information about the ROM this save state originates from. When used, this block should come before `CORE` but after `NAME`. This block is 0x12 bytes long, and it follows this structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|--------------------------------------------------|
|
||||
| 0x00 | Bytes 0x134-0x143 from the ROM (Title) |
|
||||
| 0x10 | Bytes 0x14E-0x14F from the ROM (Global checksum) |
|
||||
|
||||
#### CORE block
|
||||
|
||||
The CORE block uses the `'CORE'` identifier, and is a required block that contains both core state information, as well as basic information about the BESS version used. This block must be the first block, unless the `NAME` block exists then it must be second. An implementation should not enforce block order on blocks unknown to it for future compatibility.
|
||||
The CORE block uses the `'CORE'` identifier, and is a required block that contains both core state information, as well as basic information about the BESS version used. This block must be the first block, unless the `NAME` or `INFO` blocks exist then it must come directly after them. An implementation should not enforce block order on blocks unknown to it for future compatibility.
|
||||
|
||||
The length of the CORE block is 0xD0 bytes, but implementations are expected to ignore any excess bytes. Following the BESS block header, the structure is as follows:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|---------------------------------------|
|
||||
|--------|----------------------------------------|
|
||||
| 0x00 | Major BESS version as a 16-bit integer |
|
||||
| 0x02 | Minor BESS version as a 16-bit integer |
|
||||
|
||||
@ -97,11 +106,11 @@ The values of memory-mapped registers should be written 'as-is' to memory as if
|
||||
| 0x9C | The offset of RAM from file start (32-bit integer) |
|
||||
| 0xA0 | The size of VRAM (32-bit integer) |
|
||||
| 0xA4 | The offset of VRAM from file start (32-bit integer) |
|
||||
| 0xA9 | The size of MBC RAM (32-bit integer) |
|
||||
| 0xA8 | The size of MBC RAM (32-bit integer) |
|
||||
| 0xAC | The offset of MBC RAM from file start (32-bit integer) |
|
||||
| 0xB0 | The size of OAM (=0xA0, 32-bit integer) |
|
||||
| 0xB4 | The offset of OAM from file start (32-bit integer) |
|
||||
| 0xB9 | The size of HRAM (=0x7F, 32-bit integer) |
|
||||
| 0xB8 | The size of HRAM (=0x7F, 32-bit integer) |
|
||||
| 0xBC | The offset of HRAM from file start (32-bit integer) |
|
||||
| 0xC0 | The size of background palettes (=0x40 or 0, 32-bit integer) |
|
||||
| 0xC4 | The offset of background palettes from file start (32-bit integer) |
|
||||
|
@ -82,6 +82,12 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t multiplayer_state;
|
||||
} BESS_SGB_t;
|
||||
|
||||
typedef struct __attribute__((packed)){
|
||||
BESS_block_t header;
|
||||
char title[0x10];
|
||||
uint8_t checksum[2];
|
||||
} BESS_INFO_t;
|
||||
|
||||
/* Same RTC format as used by VBA, BGB and SameBoy in battery saves*/
|
||||
typedef struct __attribute__((packed)){
|
||||
BESS_block_t header;
|
||||
@ -241,9 +247,10 @@ size_t GB_get_save_state_size(GB_gameboy_t *gb)
|
||||
{
|
||||
return GB_get_save_state_size_no_bess(gb) +
|
||||
// BESS
|
||||
+ sizeof(BESS_CORE_t)
|
||||
+ sizeof(BESS_block_t) // NAME
|
||||
+ sizeof(BESS_NAME) - 1
|
||||
+ sizeof(BESS_INFO_t) // INFO
|
||||
+ sizeof(BESS_CORE_t)
|
||||
+ sizeof(BESS_XOAM_t)
|
||||
+ (gb->sgb? sizeof(BESS_SGB_t) : 0)
|
||||
+ bess_size_for_cartridge(gb->cartridge_type) // MBC & RTC/HUC3 block
|
||||
@ -530,6 +537,22 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool appe
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* BESS INFO */
|
||||
|
||||
static const BESS_block_t bess_info = {BE32('INFO'), LE32(sizeof(BESS_INFO_t) - sizeof(BESS_block_t))};
|
||||
|
||||
if (file->write(file, &bess_info, sizeof(bess_info)) != sizeof(bess_info)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (file->write(file, gb->rom + 0x134, 0x10) != 0x10) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (file->write(file, gb->rom + 0x14e, 2) != 2) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* BESS CORE */
|
||||
|
||||
bess_core.header = (BESS_block_t){BE32('CORE'), LE32(sizeof(bess_core) - sizeof(bess_core.header))};
|
||||
@ -936,6 +959,23 @@ static int load_bess_save(GB_gameboy_t *gb, virtual_file_t *file, bool is_samebo
|
||||
file->read(file, emulator_name, LE32(block.size));
|
||||
}
|
||||
break;
|
||||
case BE32('INFO'): {
|
||||
BESS_INFO_t bess_info = {0,};
|
||||
if (LE32(block.size) != sizeof(bess_info) - sizeof(block)) goto parse_error;
|
||||
if (file->read(file, &bess_info.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
||||
if (memcmp(bess_info.title, gb->rom + 0x134, sizeof(bess_info.title))) {
|
||||
char ascii_title[0x11] = {0,};
|
||||
for (unsigned i = 0; i < 0x10; i++) {
|
||||
if (bess_info.title[i] < 0x20 || bess_info.title[i] > 0x7E) break;
|
||||
ascii_title[i] = bess_info.title[i];
|
||||
}
|
||||
GB_log(gb, "Save state was made on another ROM: '%s'\n", ascii_title);
|
||||
}
|
||||
else if (memcmp(bess_info.checksum, gb->rom + 0x14E, 2)) {
|
||||
GB_log(gb, "Save state was potentially made on another revision of the same ROM.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BE32('XOAM'):
|
||||
if (!found_core) goto parse_error;
|
||||
if (LE32(block.size) != 96) goto parse_error;
|
||||
|
Loading…
Reference in New Issue
Block a user