diff --git a/BESS.md b/BESS.md index da601f38..ab4f3ea6 100644 --- a/BESS.md +++ b/BESS.md @@ -34,7 +34,7 @@ Every block is followed by another blocked, until the END block is reached. 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, except for the `NAME` block. -The length of the CORE block is 0xCF bytes, but implementations are expected to ignore any excess bytes. Following the BESS block header, the structure is as follows: +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 | |--------|---------------------------------------| @@ -54,7 +54,7 @@ BESS uses a four-character string to identify Game Boy models: * The third letter represents a specific CPU revision within a model, and is optional (If an implementation does not distinguish between revisions, a space character may be used). The allowed values for model GD (DMG) are `'0'` and `'A'`, through `'C'`; the allowed values for model CC (CGB) are `'0'` and `'A'`, through `'E'`; the allowed values for model CA (AGB, AGS, GBP) are `'0'`, `'A'` and `'B'`; and for every other model this value must be a space character. * The last character is used for padding and must be a space character. -For example; `'GD '` represents a DMG of an unspecified revision, `'S '` represents some model of the SGB family, and `CCE ` represent a CGB using CPU revision E. +For example; `'GD '` represents a DMG of an unspecified revision, `'S '` represents some model of the SGB family, and `'CCE '` represent a CGB using CPU revision E. | Offset | Content | |--------|-------------------------------------------------------| @@ -67,7 +67,8 @@ For example; `'GD '` represents a DMG of an unspecified revision, `'S '` repr | 0x14 | The value of IME (0 or 1) | | 0x15 | The value of the IE register | | 0x16 | Execution state (0 = running; 1 = halted; 2 = stopped) | -| 0x17 | The values of every memory-mapped register (128 bytes) | +| 0x17 | Reserved, must be 0 | +| 0x18 | The values of every memory-mapped register (128 bytes) | The values of memory-mapped registers should be written 'as-is' to memory as if the actual ROM wrote them, with the following exceptions and note: * Unused registers have Don't-Care values which should be ignored @@ -81,25 +82,26 @@ The values of memory-mapped registers should be written 'as-is' to memory as if * The value store for DIV will be used to set the internal divisor to `DIV << 8` * Implementation should apply care when ordering the write operations (For example, writes to NR52 must come before writes to the other APU registers) -|Offset | Content | -|-------|--------------------------------------------------------------------| -| 0x97 | The size of RAM (32-bit integer) | -| 0x9B | The offset of RAM from file start (32-bit integer) | -| 0x9F | The size of VRAM (32-bit integer) | -| 0xA3 | The offset of VRAM from file start (32-bit integer) | -| 0xA7 | The size of MBC RAM (32-bit integer) | -| 0xAB | The offset of MBC RAM from file start (32-bit integer) | -| 0xAF | The size of OAM (=0xA0, 32-bit integer) | -| 0xB3 | The offset of OAM from file start (32-bit integer) | -| 0xB7 | The size of HRAM (=0x7F, 32-bit integer) | -| 0xBB | The offset of HRAM from file start (32-bit integer) | -| 0xBF | The size of background palettes (=0x40 or 0, 32-bit integer) | -| 0xC3 | The offset of background palettes from file start (32-bit integer) | -| 0xC7 | The size of object palettes (=0x40 or 0, 32-bit integer) | -| 0xCB | The offset of object palettes from file start (32-bit integer) | +| Offset | Content | +|--------|--------------------------------------------------------------------| +| 0x98 | The size of RAM (32-bit integer) | +| 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) | +| 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) | +| 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) | +| 0xC8 | The size of object palettes (=0x40 or 0, 32-bit integer) | +| 0xCC | The offset of object palettes from file start (32-bit integer) | The contents of large buffers are stored outside of BESS structure so data from an implementation's native save state format can be reused. The offsets are absolute offsets from the save state file's start. Background and object palette sizes must be 0 for models prior to Game Boy Color. +An implementation needs handle size mismatches gracefully. For example, if too large MBC RAM size is specified, the superfluous data should be ignored. On the other hand, if a too small VRAM size is specified (For example, if it's a save state from an emulator emulating a CGB in DMG mode, and it didn't save the second CGB VRAM bank), the implementation is expected to set that extra bank to all zeros. #### NAME block diff --git a/Core/save_state.c b/Core/save_state.c index 8d004160..e5df68c0 100644 --- a/Core/save_state.c +++ b/Core/save_state.c @@ -50,6 +50,7 @@ typedef struct __attribute__((packed)) { uint8_t ime; uint8_t ie; uint8_t execution_mode; // 0 = running; 1 = halted; 2 = stopped + uint8_t _padding; uint8_t io_registers[0x80]; @@ -725,6 +726,10 @@ static void read_bess_buffer(const BESS_buffer_t *buffer, virtual_file_t *file, file->seek(file, LE32(buffer->offset), SEEK_SET); file->read(file, dest, MIN(LE32(buffer->size), max_size)); file->seek(file, pos, SEEK_SET); + + if (LE32(buffer->size) < max_size) { + memset(dest + LE32(buffer->size), 0, max_size - LE32(buffer->size)); + } } static int load_bess_save(GB_gameboy_t *gb, virtual_file_t *file, bool is_sameboy)