Added optional INFO block

This commit is contained in:
Lior Halphon 2021-04-15 21:57:38 +03:00
parent 2078c2a8fb
commit f0a6488546
2 changed files with 55 additions and 6 deletions

19
BESS.md
View File

@ -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 |
|--------|---------------------------------------|
| 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) |

View File

@ -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;