SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
Core/save_state.c
1 #include "gb.h"
2 #include <stdio.h>
3 #include <errno.h>
4 #include <assert.h>
5 #include <string.h>
6 #include <stdlib.h>
7
8 #ifdef GB_BIG_ENDIAN
9 #define BESS_NAME "SameBoy v" GB_VERSION " (Big Endian)"
10 #else
11 #define BESS_NAME "SameBoy v" GB_VERSION
12 #endif
13
14 _Static_assert((GB_SECTION_OFFSET(core_state) & 7) == 0, "Section core_state is not aligned");
15 _Static_assert((GB_SECTION_OFFSET(dma) & 7) == 0, "Section dma is not aligned");
16 _Static_assert((GB_SECTION_OFFSET(mbc) & 7) == 0, "Section mbc is not aligned");
17 _Static_assert((GB_SECTION_OFFSET(hram) & 7) == 0, "Section hram is not aligned");
18 _Static_assert((GB_SECTION_OFFSET(timing) & 7) == 0, "Section timing is not aligned");
19 _Static_assert((GB_SECTION_OFFSET(apu) & 7) == 0, "Section apu is not aligned");
20 _Static_assert((GB_SECTION_OFFSET(rtc) & 7) == 0, "Section rtc is not aligned");
21 _Static_assert((GB_SECTION_OFFSET(video) & 7) == 0, "Section video is not aligned");
22 _Static_assert((GB_SECTION_OFFSET(accessory) & 7) == 0, "Section accessory is not aligned");
23
24 typedef struct __attribute__((packed)) {
25 uint32_t magic;
26 uint32_t size;
27 } BESS_block_t;
28
29 typedef struct __attribute__((packed)) {
30 uint32_t size;
31 uint32_t offset;
32 } BESS_buffer_t;
33
34 typedef struct __attribute__((packed)) {
35 uint32_t start_offset;
36 uint32_t magic;
37 } BESS_footer_t;
38
39 typedef struct __attribute__((packed)) {
40 BESS_block_t header;
41 uint16_t major;
42 uint16_t minor;
43 union {
44 struct {
45 char family;
46 char model;
47 char revision;
48 char padding;
49 };
50 uint32_t full_model;
51 };
52
53 uint16_t pc;
54 uint16_t af;
55 uint16_t bc;
56 uint16_t de;
57 uint16_t hl;
58 uint16_t sp;
59
60 uint8_t ime;
61 uint8_t ie;
62 uint8_t execution_mode; // 0 = running; 1 = halted; 2 = stopped
63 uint8_t _padding;
64
65 uint8_t io_registers[0x80];
66
67 BESS_buffer_t ram;
68 BESS_buffer_t vram;
69 BESS_buffer_t mbc_ram;
70 BESS_buffer_t oam;
71 BESS_buffer_t hram;
72 BESS_buffer_t background_palettes;
73 BESS_buffer_t object_palettes;
74 } BESS_CORE_t;
75
76 typedef struct __attribute__((packed)) {
77 BESS_block_t header;
78 uint8_t extra_oam[96];
79 } BESS_XOAM_t;
80
81 typedef struct __attribute__((packed)) {
82 BESS_block_t header;
83 BESS_buffer_t border_tiles;
84 BESS_buffer_t border_tilemap;
85 BESS_buffer_t border_palettes;
86
87 BESS_buffer_t active_palettes;
88 BESS_buffer_t ram_palettes;
89 BESS_buffer_t attribute_map;
90 BESS_buffer_t attribute_files;
91
92 uint8_t multiplayer_state;
93 } BESS_SGB_t;
94
95 typedef struct __attribute__((packed)){
96 BESS_block_t header;
97 char title[0x10];
98 uint8_t checksum[2];
99 } BESS_INFO_t;
100
101 /* Same RTC format as used by VBA, BGB and SameBoy in battery saves*/
102 typedef struct __attribute__((packed)){
103 BESS_block_t header;
104 struct {
105 uint8_t seconds;
106 uint8_t padding1[3];
107 uint8_t minutes;
108 uint8_t padding2[3];
109 uint8_t hours;
110 uint8_t padding3[3];
111 uint8_t days;
112 uint8_t padding4[3];
113 uint8_t high;
114 uint8_t padding5[3];
115 } real, latched;
116 uint64_t last_rtc_second;
117 } BESS_RTC_t;
118
119 /* Same HuC3 RTC format as used by SameBoy and BGB in battery saves */
120 typedef struct __attribute__((packed)){
121 BESS_block_t header;
122 GB_huc3_rtc_time_t data;
123 } BESS_HUC3_t;
124
125 typedef struct __attribute__((packed)) {
126 BESS_block_t header;
127
128 // Flags
129 bool latch_ready:1;
130 bool eeprom_do:1;
131 bool eeprom_di:1;
132 bool eeprom_clk:1;
133 bool eeprom_cs:1;
134 bool eeprom_write_enabled:1;
135 uint8_t padding:2;
136
137 uint8_t argument_bits_left;
138
139 uint16_t eeprom_command;
140 uint16_t read_bits;
141
142 uint16_t x_latch;
143 uint16_t y_latch;
144
145 } BESS_MBC7_t;
146
147 typedef struct __attribute__((packed)){
148 BESS_block_t header;
149 uint64_t last_rtc_second;
150 uint8_t real_rtc_data[4];
151 uint8_t latched_rtc_data[4];
152 uint8_t mr4;
153 } BESS_TPP1_t;
154
155 typedef struct __attribute__((packed)) {
156 uint16_t address;
157 uint8_t value;
158 } BESS_MBC_pair_t;
159
160 typedef struct virtual_file_s virtual_file_t;
161 struct virtual_file_s
162 {
163 size_t (*read)(virtual_file_t *file, void *dest, size_t length);
164 size_t (*write)(virtual_file_t *file, const void *dest, size_t length);
165 void (*seek)(virtual_file_t *file, ssize_t ammount, int origin);
166 size_t (*tell)(virtual_file_t *file);
167 union {
168 FILE *file;
169 struct {
170 uint8_t *buffer;
171 size_t position;
172 size_t size;
173 };
174 };
175 };
176
177 static size_t file_read(virtual_file_t *file, void *dest, size_t length)
178 {
179 return fread(dest, 1, length, file->file);
180 }
181
182 static void file_seek(virtual_file_t *file, ssize_t ammount, int origin)
183 {
184 fseek(file->file, ammount, origin);
185 }
186
187 static size_t file_write(virtual_file_t *file, const void *src, size_t length)
188 {
189 return fwrite(src, 1, length, file->file);
190 }
191
192 static size_t file_tell(virtual_file_t *file)
193 {
194 return ftell(file->file);
195 }
196
197 static size_t buffer_read(virtual_file_t *file, void *dest, size_t length)
198 {
199 if (length & 0x80000000) {
200 return 0;
201 }
202 errno = 0;
203 if (length > file->size - file->position) {
204 errno = EIO;
205 length = file->size - file->position;
206 }
207
208 memcpy(dest, file->buffer + file->position, length);
209 file->position += length;
210
211 return length;
212 }
213
214 static void buffer_seek(virtual_file_t *file, ssize_t ammount, int origin)
215 {
216 switch (origin) {
217 case SEEK_SET:
218 file->position = ammount;
219 break;
220 case SEEK_CUR:
221 file->position += ammount;
222 break;
223 case SEEK_END:
224 file->position = file->size + ammount;
225 break;
226 default:
227 break;
228 }
229
230 if (file->position > file->size) {
231 file->position = file->size;
232 }
233 }
234
235 static size_t buffer_write(virtual_file_t *file, const void *src, size_t size)
236 {
237 memcpy(file->buffer + file->position, src, size);
238 file->position += size;
239 return size;
240 }
241
242 static size_t buffer_tell(virtual_file_t *file)
243 {
244 return file->position;
245 }
246
247 static size_t bess_size_for_cartridge(const GB_cartridge_t *cart)
248 {
249 switch (cart->mbc_type) {
250 default:
251 case GB_NO_MBC: return 0;
252 case GB_MBC1:
253 return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
254 case GB_MBC2:
255 return sizeof(BESS_block_t) + 2 * sizeof(BESS_MBC_pair_t);
256 case GB_MBC3:
257 return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + (cart->has_rtc? sizeof(BESS_RTC_t) : 0);
258 case GB_MBC5:
259 return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
260 case GB_CAMERA:
261 return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t);
262 case GB_MBC7:
263 return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_MBC7_t);
264 case GB_MMM01:
265 return sizeof(BESS_block_t) + 8 * sizeof(BESS_MBC_pair_t);
266 case GB_HUC1:
267 return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t);
268 case GB_HUC3:
269 return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_HUC3_t);
270 case GB_TPP1:
271 return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_TPP1_t);
272 }
273 }
274
275 size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb)
276 {
277 return GB_SECTION_SIZE(header)
278 + GB_SECTION_SIZE(core_state) + sizeof(uint32_t)
279 + GB_SECTION_SIZE(dma ) + sizeof(uint32_t)
280 + GB_SECTION_SIZE(mbc ) + sizeof(uint32_t)
281 + GB_SECTION_SIZE(hram ) + sizeof(uint32_t)
282 + GB_SECTION_SIZE(timing ) + sizeof(uint32_t)
283 + GB_SECTION_SIZE(apu ) + sizeof(uint32_t)
284 + GB_SECTION_SIZE(rtc ) + sizeof(uint32_t)
285 + GB_SECTION_SIZE(video ) + sizeof(uint32_t)
286 + GB_SECTION_SIZE(accessory ) + sizeof(uint32_t)
287 + (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0)
288 + gb->mbc_ram_size
289 + gb->ram_size
290 + gb->vram_size;
291 }
292
293 size_t GB_get_save_state_size(GB_gameboy_t *gb)
294 {
295 return GB_get_save_state_size_no_bess(gb) +
296 // BESS
297 + sizeof(BESS_block_t) // NAME
298 + sizeof(BESS_NAME) - 1
299 + sizeof(BESS_INFO_t) // INFO
300 + sizeof(BESS_CORE_t)
301 + sizeof(BESS_XOAM_t)
302 + (gb->sgb? sizeof(BESS_SGB_t) : 0)
303 + bess_size_for_cartridge(gb->cartridge_type) // MBC & RTC/HUC3/TPP1/MBC7 block
304 + sizeof(BESS_block_t) // END block
305 + sizeof(BESS_footer_t);
306 }
307
308 static bool verify_and_update_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save, bool *attempt_bess)
309 {
310 *attempt_bess = false;
311
312 if (gb->version != save->version) {
313 GB_log(gb, "The save state is for a different version of SameBoy.\n");
314 *attempt_bess = true;
315 return false;
316 }
317
318 if (GB_is_cgb(gb) != GB_is_cgb(save) || GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) {
319 GB_log(gb, "The save state is for a different Game Boy model. Try changing the emulated model.\n");
320 return false;
321 }
322
323 if (gb->mbc_ram_size < save->mbc_ram_size) {
324 GB_log(gb, "The save state has non-matching MBC RAM size.\n");
325 return false;
326 }
327
328 if (gb->vram_size != save->vram_size) {
329 GB_log(gb, "The save state has non-matching VRAM size. Try changing the emulated model.\n");
330 return false;
331 }
332
333 if (GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) {
334 GB_log(gb, "The save state is %sfor a Super Game Boy. Try changing the emulated model.\n", GB_is_hle_sgb(save)? "" : "not ");
335 return false;
336 }
337
338 if (gb->ram_size != save->ram_size) {
339 GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n");
340 return false;
341 }
342
343 if (gb->accessory != save->accessory) {
344 memset(GB_GET_SECTION(save, accessory), 0, GB_SECTION_SIZE(accessory));
345 }
346
347 switch (save->model) {
348 case GB_MODEL_DMG_B: return true;
349 case GB_MODEL_SGB_NTSC: return true;
350 case GB_MODEL_SGB_PAL: return true;
351 case GB_MODEL_SGB_NTSC_NO_SFC: return true;
352 case GB_MODEL_SGB_PAL_NO_SFC: return true;
353 case GB_MODEL_MGB: return true;
354 case GB_MODEL_SGB2: return true;
355 case GB_MODEL_SGB2_NO_SFC: return true;
356 case GB_MODEL_CGB_0: return true;
357 case GB_MODEL_CGB_A: return true;
358 case GB_MODEL_CGB_B: return true;
359 case GB_MODEL_CGB_C: return true;
360 case GB_MODEL_CGB_D: return true;
361 case GB_MODEL_CGB_E: return true;
362 case GB_MODEL_AGB_A: return true;
363 case GB_MODEL_GBP_A: return true;
364 }
365 if ((gb->model & GB_MODEL_FAMILY_MASK) == (save->model & GB_MODEL_FAMILY_MASK)) {
366 save->model = gb->model;
367 return true;
368 }
369
370 GB_log(gb, "This save state is for an unknown Game Boy model\n");
371 return false;
372 }
373
374 static void sanitize_state(GB_gameboy_t *gb)
375 {
376 for (unsigned i = 0; i < 32; i++) {
377 GB_palette_changed(gb, false, i * 2);
378 GB_palette_changed(gb, true, i * 2);
379 }
380
381 gb->bg_fifo.read_end &= GB_FIFO_LENGTH - 1;
382 gb->oam_fifo.read_end &= GB_FIFO_LENGTH - 1;
383 gb->last_tile_index_address &= 0x1FFF;
384 gb->window_tile_x &= 0x1F;
385
386 /* These are kind of DOS-ish if too large */
387 if (abs(gb->display_cycles) > 0x80000) {
388 gb->display_cycles = 0;
389 }
390
391 if (abs(gb->div_cycles) > 0x8000) {
392 gb->div_cycles = 0;
393 }
394
395 if (!GB_is_cgb(gb)) {
396 gb->cgb_mode = false;
397 }
398
399 if (gb->ram_size == 0x8000) {
400 gb->cgb_ram_bank &= 0x7;
401 }
402 else {
403 gb->cgb_ram_bank = 1;
404 }
405 if (gb->vram_size != 0x4000) {
406 gb->cgb_vram_bank = 0;
407 }
408 if (!GB_is_cgb(gb)) {
409 gb->current_tile_attributes = 0;
410 }
411
412 gb->object_low_line_address &= (gb->vram_size - 1) & ~1;
413 if (gb->lcd_x > gb->position_in_line) {
414 gb->lcd_x = gb->position_in_line;
415 }
416
417 if (gb->sgb) {
418 if (gb->sgb->player_count != 1 && gb->sgb->player_count != 2 && gb->sgb->player_count != 4) {
419 gb->sgb->player_count = 1;
420 }
421 gb->sgb->current_player &= gb->sgb->player_count - 1;
422 }
423 GB_update_clock_rate(gb);
424
425 if (gb->camera_update_request_callback) {
426 GB_camera_updated(gb);
427 }
428
429 if (!gb->apu.apu_cycles_in_2mhz) {
430 gb->apu.apu_cycles >>= 2;
431 gb->apu.apu_cycles_in_2mhz = true;
432 }
433
434 if (gb->n_visible_objs > 10) {
435 gb->n_visible_objs = 10;
436 }
437 }
438
439 static bool dump_section(virtual_file_t *file, const void *src, uint32_t size)
440 {
441 if (file->write(file, &size, sizeof(size)) != sizeof(size)) {
442 return false;
443 }
444
445 if (file->write(file, src, size) != size) {
446 return false;
447 }
448
449 return true;
450 }
451
452 #define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
453
454 static int save_bess_mbc_block(GB_gameboy_t *gb, virtual_file_t *file)
455 {
456
457 BESS_block_t mbc_block = {BE32('MBC '), 0};
458 BESS_MBC_pair_t pairs[8];
459 switch (gb->cartridge_type->mbc_type) {
460 default:
461 case GB_NO_MBC: return 0;
462 case GB_MBC1:
463 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
464 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc1.bank_low};
465 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc1.bank_high};
466 pairs[3] = (BESS_MBC_pair_t){LE16(0x6000), gb->mbc1.mode};
467 mbc_block.size = 4 * sizeof(pairs[0]);
468 break;
469 case GB_MBC2:
470 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
471 pairs[1] = (BESS_MBC_pair_t){LE16(0x0100), gb->mbc2.rom_bank};
472 mbc_block.size = 2 * sizeof(pairs[0]);
473 break;
474 case GB_MBC3:
475 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
476 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc3.rom_bank};
477 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc3.ram_bank | (gb->mbc3.rtc_mapped? 8 : 0)};
478 mbc_block.size = 3 * sizeof(pairs[0]);
479 break;
480 case GB_MBC5:
481 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
482 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc5.rom_bank_low};
483 pairs[2] = (BESS_MBC_pair_t){LE16(0x3000), gb->mbc5.rom_bank_high};
484 pairs[3] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
485 mbc_block.size = 4 * sizeof(pairs[0]);
486 break;
487 case GB_CAMERA:
488 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
489 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc5.rom_bank_low};
490 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
491 mbc_block.size = 3 * sizeof(pairs[0]);
492 break;
493 case GB_MBC7:
494 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
495 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc7.rom_bank};
496 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc7.secondary_ram_enable? 0x40 : 0};
497 mbc_block.size = 3 * sizeof(pairs[0]);
498 break;
499 case GB_MMM01:
500 pairs[0] = (BESS_MBC_pair_t){LE16(0x2000), (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) | (gb->mmm01.rom_bank_mid << 5)};
501 pairs[1] = (BESS_MBC_pair_t){LE16(0x6000), gb->mmm01.mbc1_mode | (gb->mmm01.rom_bank_mask << 2) | (gb->mmm01.multiplex_mode << 6)};
502 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2) | (gb->mmm01.rom_bank_high << 4) | (gb->mmm01.mbc1_mode_disable << 6)};
503 pairs[3] = (BESS_MBC_pair_t){LE16(0x0000), (gb->mbc_ram_enable? 0xA : 0x0) | (gb->mmm01.ram_bank_mask << 4) | (gb->mmm01.locked << 6)};
504 /* For compatibility with emulators that inaccurately emulate MMM01, and also require two writes per register */
505 pairs[4] = (BESS_MBC_pair_t){LE16(0x2000), (gb->mmm01.rom_bank_low & ~(gb->mmm01.rom_bank_mask << 1))};
506 pairs[5] = pairs[1];
507 pairs[6] = pairs[2];
508 pairs[7] = pairs[3];
509 mbc_block.size = 8 * sizeof(pairs[0]);
510 break;
511 case GB_HUC1:
512 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc1.ir_mode? 0xE : 0x0};
513 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc1.bank_low};
514 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc1.bank_high};
515 mbc_block.size = 3 * sizeof(pairs[0]);
516 case GB_HUC3:
517 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc3.mode};
518 pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc3.rom_bank};
519 pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc3.ram_bank};
520 mbc_block.size = 3 * sizeof(pairs[0]);
521 break;
522 case GB_TPP1:
523 pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->tpp1.rom_bank};
524 pairs[1] = (BESS_MBC_pair_t){LE16(0x0001), gb->tpp1.rom_bank >> 8};
525 pairs[2] = (BESS_MBC_pair_t){LE16(0x0002), gb->tpp1.rom_bank};
526 pairs[3] = (BESS_MBC_pair_t){LE16(0x0003), gb->tpp1.mode};
527 mbc_block.size = 4 * sizeof(pairs[0]);
528 break;
529 }
530
531 mbc_block.size = LE32(mbc_block.size);
532
533 if (file->write(file, &mbc_block, sizeof(mbc_block)) != sizeof(mbc_block)) {
534 return errno;
535 }
536
537 if (file->write(file, &pairs, LE32(mbc_block.size)) != LE32(mbc_block.size)) {
538 return errno;
539 }
540
541 return 0;
542 }
543
544 static const uint8_t *get_header_bank(GB_gameboy_t *gb)
545 {
546 if (gb->cartridge_type->mbc_type == GB_MMM01) {
547 return gb->rom + gb->rom_size - 0x8000;
548 }
549 return gb->rom;
550 }
551
552 static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool append_bess)
553 {
554 errno = 0;
555 if (file->write(file, GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) goto error;
556 if (!DUMP_SECTION(gb, file, core_state)) goto error;
557 if (!DUMP_SECTION(gb, file, dma )) goto error;
558 if (!DUMP_SECTION(gb, file, mbc )) goto error;
559 uint32_t hram_offset = file->tell(file) + 4;
560 if (!DUMP_SECTION(gb, file, hram )) goto error;
561 if (!DUMP_SECTION(gb, file, timing )) goto error;
562 if (!DUMP_SECTION(gb, file, apu )) goto error;
563 if (!DUMP_SECTION(gb, file, rtc )) goto error;
564 uint32_t video_offset = file->tell(file) + 4;
565 if (!DUMP_SECTION(gb, file, video )) goto error;
566 if (!DUMP_SECTION(gb, file, accessory )) goto error;
567
568 uint32_t sgb_offset = 0;
569
570 if (GB_is_hle_sgb(gb)) {
571 sgb_offset = file->tell(file) + 4;
572 if (!dump_section(file, gb->sgb, sizeof(*gb->sgb))) goto error;
573 }
574
575
576 BESS_CORE_t bess_core = {0,};
577
578 bess_core.mbc_ram.offset = LE32(file->tell(file));
579 bess_core.mbc_ram.size = LE32(gb->mbc_ram_size);
580 if (file->write(file, gb->mbc_ram, gb->mbc_ram_size) != gb->mbc_ram_size) {
581 goto error;
582 }
583
584 bess_core.ram.offset = LE32(file->tell(file));
585 bess_core.ram.size = LE32(gb->ram_size);
586 if (file->write(file, gb->ram, gb->ram_size) != gb->ram_size) {
587 goto error;
588 }
589
590 bess_core.vram.offset = LE32(file->tell(file));
591 bess_core.vram.size = LE32(gb->vram_size);
592 if (file->write(file, gb->vram, gb->vram_size) != gb->vram_size) {
593 goto error;
594 }
595
596 if (!append_bess) return 0;
597
598 BESS_footer_t bess_footer = {
599 .start_offset = LE32(file->tell(file)),
600 .magic = BE32('BESS'),
601 };
602
603 /* BESS NAME */
604
605 static const BESS_block_t bess_name = {BE32('NAME'), LE32(sizeof(BESS_NAME) - 1)};
606
607 if (file->write(file, &bess_name, sizeof(bess_name)) != sizeof(bess_name)) {
608 goto error;
609 }
610
611 if (file->write(file, BESS_NAME, sizeof(BESS_NAME) - 1) != sizeof(BESS_NAME) - 1) {
612 goto error;
613 }
614
615 /* BESS INFO */
616
617 static const BESS_block_t bess_info = {BE32('INFO'), LE32(sizeof(BESS_INFO_t) - sizeof(BESS_block_t))};
618
619 if (file->write(file, &bess_info, sizeof(bess_info)) != sizeof(bess_info)) {
620 goto error;
621 }
622
623 const uint8_t *bank = get_header_bank(gb);
624
625 if (file->write(file, bank + 0x134, 0x10) != 0x10) {
626 goto error;
627 }
628
629 if (file->write(file, bank + 0x14E, 2) != 2) {
630 goto error;
631 }
632
633 /* BESS CORE */
634
635 bess_core.header = (BESS_block_t){BE32('CORE'), LE32(sizeof(bess_core) - sizeof(bess_core.header))};
636 bess_core.major = LE16(1);
637 bess_core.minor = LE16(1);
638 switch (gb->model) {
639
640 case GB_MODEL_DMG_B: bess_core.full_model = BE32('GDB '); break;
641 case GB_MODEL_MGB: bess_core.full_model = BE32('GM '); break;
642
643 case GB_MODEL_SGB_NTSC:
644 case GB_MODEL_SGB_NTSC_NO_SFC:
645 bess_core.full_model = BE32('SN '); break;
646
647 case GB_MODEL_SGB_PAL_NO_SFC:
648 case GB_MODEL_SGB_PAL:
649 bess_core.full_model = BE32('SP '); break;
650
651 case GB_MODEL_SGB2_NO_SFC:
652 case GB_MODEL_SGB2:
653 bess_core.full_model = BE32('S2 '); break;
654
655 case GB_MODEL_CGB_0: bess_core.full_model = BE32('CC0 '); break;
656 case GB_MODEL_CGB_A: bess_core.full_model = BE32('CCA '); break;
657 case GB_MODEL_CGB_B: bess_core.full_model = BE32('CCB '); break;
658 case GB_MODEL_CGB_C: bess_core.full_model = BE32('CCC '); break;
659 case GB_MODEL_CGB_D: bess_core.full_model = BE32('CCD '); break;
660 case GB_MODEL_CGB_E: bess_core.full_model = BE32('CCE '); break;
661 case GB_MODEL_AGB_A:
662 case GB_MODEL_GBP_A:
663 bess_core.full_model = BE32('CAA '); break;
664 }
665
666 bess_core.pc = LE16(gb->pc);
667 bess_core.af = LE16(gb->af);
668 bess_core.bc = LE16(gb->bc);
669 bess_core.de = LE16(gb->de);
670 bess_core.hl = LE16(gb->hl);
671 bess_core.sp = LE16(gb->sp);
672
673 bess_core.ime = gb->ime;
674 bess_core.ie = gb->interrupt_enable;
675 bess_core.execution_mode = 0;
676 if (gb->halted) {
677 bess_core.execution_mode = 1;
678 }
679 else if (gb->stopped) {
680 bess_core.execution_mode = 2;
681 }
682
683 memcpy(bess_core.io_registers, gb->io_registers, sizeof(gb->io_registers));
684 bess_core.io_registers[GB_IO_DIV] = gb->div_counter >> 8;
685 bess_core.io_registers[GB_IO_BANK] = gb->boot_rom_finished;
686 bess_core.io_registers[GB_IO_KEY1] |= gb->cgb_double_speed? 0x80 : 0;
687 bess_core.hram.size = LE32(sizeof(gb->hram));
688 bess_core.hram.offset = LE32(hram_offset + offsetof(GB_gameboy_t, hram) - GB_SECTION_OFFSET(hram));
689 bess_core.oam.size = LE32(sizeof(gb->oam));
690 bess_core.oam.offset = LE32(video_offset + offsetof(GB_gameboy_t, oam) - GB_SECTION_OFFSET(video));
691 if (GB_is_cgb(gb)) {
692 bess_core.background_palettes.size = LE32(sizeof(gb->background_palettes_data));
693 bess_core.background_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, background_palettes_data) - GB_SECTION_OFFSET(video));
694 bess_core.object_palettes.size = LE32(sizeof(gb->object_palettes_data));
695 bess_core.object_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, object_palettes_data) - GB_SECTION_OFFSET(video));
696 }
697
698 if (file->write(file, &bess_core, sizeof(bess_core)) != sizeof(bess_core)) {
699 goto error;
700 }
701
702 /* BESS XOAM */
703
704 BESS_XOAM_t bess_xoam = {0,};
705 bess_xoam.header = (BESS_block_t){BE32('XOAM'), LE32(sizeof(bess_xoam) - sizeof(bess_xoam.header))};
706 if (GB_is_cgb(gb)) {
707 memcpy(bess_xoam.extra_oam, gb->extra_oam, sizeof(bess_xoam.extra_oam));
708 }
709
710 if (file->write(file, &bess_xoam, sizeof(bess_xoam)) != sizeof(bess_xoam)) {
711 goto error;
712 }
713
714 save_bess_mbc_block(gb, file);
715 if (gb->cartridge_type->has_rtc) {
716 if (gb->cartridge_type ->mbc_type == GB_TPP1) {
717 BESS_TPP1_t bess_tpp1 = {0,};
718 bess_tpp1.header = (BESS_block_t){BE32('TPP1'), LE32(sizeof(bess_tpp1) - sizeof(bess_tpp1.header))};
719
720 bess_tpp1.last_rtc_second = LE64(gb->last_rtc_second);
721 unrolled for (unsigned i = 4; i--;) {
722 bess_tpp1.real_rtc_data[i] = gb->rtc_real.data[i ^ 3];
723 bess_tpp1.latched_rtc_data[i] = gb->rtc_latched.data[i ^ 3];
724 }
725 bess_tpp1.mr4 = gb->tpp1_mr4;
726
727 if (file->write(file, &bess_tpp1, sizeof(bess_tpp1)) != sizeof(bess_tpp1)) {
728 goto error;
729 }
730 }
731 else if (gb->cartridge_type ->mbc_type != GB_HUC3) {
732 BESS_RTC_t bess_rtc = {0,};
733 bess_rtc.header = (BESS_block_t){BE32('RTC '), LE32(sizeof(bess_rtc) - sizeof(bess_rtc.header))};
734 bess_rtc.real.seconds = gb->rtc_real.seconds;
735 bess_rtc.real.minutes = gb->rtc_real.minutes;
736 bess_rtc.real.hours = gb->rtc_real.hours;
737 bess_rtc.real.days = gb->rtc_real.days;
738 bess_rtc.real.high = gb->rtc_real.high;
739 bess_rtc.latched.seconds = gb->rtc_latched.seconds;
740 bess_rtc.latched.minutes = gb->rtc_latched.minutes;
741 bess_rtc.latched.hours = gb->rtc_latched.hours;
742 bess_rtc.latched.days = gb->rtc_latched.days;
743 bess_rtc.latched.high = gb->rtc_latched.high;
744 bess_rtc.last_rtc_second = LE64(gb->last_rtc_second);
745 if (file->write(file, &bess_rtc, sizeof(bess_rtc)) != sizeof(bess_rtc)) {
746 goto error;
747 }
748 }
749 else {
750 BESS_HUC3_t bess_huc3 = {0,};
751 bess_huc3.header = (BESS_block_t){BE32('HUC3'), LE32(sizeof(bess_huc3) - sizeof(bess_huc3.header))};
752
753 bess_huc3.data = (GB_huc3_rtc_time_t) {
754 LE64(gb->last_rtc_second),
755 LE16(gb->huc3.minutes),
756 LE16(gb->huc3.days),
757 LE16(gb->huc3.alarm_minutes),
758 LE16(gb->huc3.alarm_days),
759 gb->huc3.alarm_enabled,
760 };
761 if (file->write(file, &bess_huc3, sizeof(bess_huc3)) != sizeof(bess_huc3)) {
762 goto error;
763 }
764 }
765 }
766
767 if (gb->cartridge_type ->mbc_type == GB_MBC7) {
768 BESS_MBC7_t bess_mbc7 = {
769 .latch_ready = gb->mbc7.latch_ready,
770 .eeprom_do = gb->mbc7.eeprom_do,
771 .eeprom_di = gb->mbc7.eeprom_di,
772 .eeprom_clk = gb->mbc7.eeprom_clk,
773 .eeprom_cs = gb->mbc7.eeprom_cs,
774 .eeprom_write_enabled = gb->mbc7.eeprom_write_enabled,
775
776 .argument_bits_left = gb->mbc7.argument_bits_left,
777
778 .eeprom_command = LE16(gb->mbc7.eeprom_command),
779 .read_bits = LE16(gb->mbc7.read_bits),
780
781 .x_latch = LE16(gb->mbc7.x_latch),
782 .y_latch = LE16(gb->mbc7.y_latch),
783 };
784 bess_mbc7.header = (BESS_block_t){BE32('MBC7'), LE32(sizeof(bess_mbc7) - sizeof(bess_mbc7.header))};
785
786 if (file->write(file, &bess_mbc7, sizeof(bess_mbc7)) != sizeof(bess_mbc7)) {
787 goto error;
788 }
789 }
790
791 bool needs_sgb_padding = false;
792 if (gb->sgb) {
793 /* BESS SGB */
794 if (gb->sgb->disable_commands) {
795 needs_sgb_padding = true;
796 }
797 else {
798 BESS_SGB_t bess_sgb = {{BE32('SGB '), LE32(sizeof(bess_sgb) - sizeof(bess_sgb.header))}, };
799
800 bess_sgb.border_tiles = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.tiles)),
801 LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.tiles))};
802 bess_sgb.border_tilemap = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.map)),
803 LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.map))};
804 bess_sgb.border_palettes = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.palette)),
805 LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.palette))};
806
807 bess_sgb.active_palettes = (BESS_buffer_t){LE32(sizeof(gb->sgb->effective_palettes)),
808 LE32(sgb_offset + offsetof(GB_sgb_t, effective_palettes))};
809 bess_sgb.ram_palettes = (BESS_buffer_t){LE32(sizeof(gb->sgb->ram_palettes)),
810 LE32(sgb_offset + offsetof(GB_sgb_t, ram_palettes))};
811 bess_sgb.attribute_map = (BESS_buffer_t){LE32(sizeof(gb->sgb->attribute_map)),
812 LE32(sgb_offset + offsetof(GB_sgb_t, attribute_map))};
813 bess_sgb.attribute_files = (BESS_buffer_t){LE32(sizeof(gb->sgb->attribute_files)),
814 LE32(sgb_offset + offsetof(GB_sgb_t, attribute_files))};
815
816 bess_sgb.multiplayer_state = (gb->sgb->player_count << 4) | gb->sgb->current_player;
817 if (file->write(file, &bess_sgb, sizeof(bess_sgb)) != sizeof(bess_sgb)) {
818 goto error;
819 }
820 }
821 }
822
823 /* BESS END */
824
825 static const BESS_block_t bess_end = {BE32('END '), 0};
826
827 if (file->write(file, &bess_end, sizeof(bess_end)) != sizeof(bess_end)) {
828 goto error;
829 }
830
831 if (needs_sgb_padding) {
832 static const uint8_t sgb_padding[sizeof(BESS_SGB_t)] = {0,};
833 file->write(file, sgb_padding, sizeof(sgb_padding));
834 }
835
836 /* BESS Footer */
837
838 if (file->write(file, &bess_footer, sizeof(bess_footer)) != sizeof(bess_footer)) {
839 goto error;
840 }
841
842 return 0;;
843 error:
844 if (errno == 0) return EIO;
845 return errno;
846 }
847
848 int GB_save_state(GB_gameboy_t *gb, const char *path)
849 {
850 GB_ASSERT_NOT_RUNNING(gb)
851 FILE *f = fopen(path, "wb");
852 if (!f) {
853 GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
854 return errno;
855 }
856 virtual_file_t file = {
857 .write = file_write,
858 .seek = file_seek,
859 .tell = file_tell,
860 .file = f,
861 };
862 int ret = save_state_internal(gb, &file, true);
863 fclose(f);
864 return ret;
865 }
866
867 void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer)
868 {
869 GB_ASSERT_NOT_RUNNING(gb)
870 virtual_file_t file = {
871 .write = buffer_write,
872 .seek = buffer_seek,
873 .tell = buffer_tell,
874 .buffer = (uint8_t *)buffer,
875 .position = 0,
876 };
877
878 save_state_internal(gb, &file, true);
879 assert(file.position == GB_get_save_state_size(gb));
880 }
881
882 void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer)
883 {
884 virtual_file_t file = {
885 .write = buffer_write,
886 .seek = buffer_seek,
887 .tell = buffer_tell,
888 .buffer = (uint8_t *)buffer,
889 .position = 0,
890 };
891
892 save_state_internal(gb, &file, false);
893 assert(file.position == GB_get_save_state_size_no_bess(gb));
894 }
895
896 static bool read_section(virtual_file_t *file, void *dest, uint32_t size)
897 {
898 uint32_t saved_size = 0;
899 if (file->read(file, &saved_size, sizeof(size)) != sizeof(size)) {
900 return false;
901 }
902
903 if (saved_size <= size) {
904 if (file->read(file, dest, saved_size) != saved_size) {
905 return false;
906 }
907 }
908 else {
909 if (file->read(file, dest, size) != size) {
910 return false;
911 }
912 file->seek(file, saved_size - size, SEEK_CUR);
913 }
914
915 return true;
916 }
917
918 static void read_bess_buffer(const BESS_buffer_t *buffer, virtual_file_t *file, uint8_t *dest, size_t max_size)
919 {
920 size_t pos = file->tell(file);
921 file->seek(file, LE32(buffer->offset), SEEK_SET);
922 file->read(file, dest, MIN(LE32(buffer->size), max_size));
923 file->seek(file, pos, SEEK_SET);
924
925 if (LE32(buffer->size) < max_size) {
926 memset(dest + LE32(buffer->size), 0, max_size - LE32(buffer->size));
927 }
928 }
929
930 static int load_bess_save(GB_gameboy_t *gb, virtual_file_t *file, bool is_sameboy)
931 {
932 char emulator_name[65] = {0,};
933 file->seek(file, -sizeof(BESS_footer_t), SEEK_END);
934 BESS_footer_t footer = {0, };
935 file->read(file, &footer, sizeof(footer));
936 if (footer.magic != BE32('BESS')) {
937 // Not a BESS file
938 if (!is_sameboy) {
939 GB_log(gb, "The file is not a save state, or is from an incompatible operating system.\n");
940 }
941 return -1;
942 }
943
944 GB_gameboy_t save;
945 GB_init(&save, gb->model);
946 save.cartridge_type = gb->cartridge_type;
947
948 file->seek(file, LE32(footer.start_offset), SEEK_SET);
949 bool found_core = false;
950 BESS_CORE_t core = {0,};
951 bool found_sgb = false;
952 BESS_SGB_t sgb = {0,};
953 while (true) {
954 BESS_block_t block;
955 if (file->read(file, &block, sizeof(block)) != sizeof(block)) goto error;
956 switch (block.magic) {
957 case BE32('CORE'):
958 if (found_core) goto parse_error;
959 found_core = true;
960 if (LE32(block.size) > sizeof(core) - sizeof(block)) {
961 if (file->read(file, &core.header + 1, sizeof(core) - sizeof(block)) != sizeof(core) - sizeof(block)) goto error;
962 file->seek(file, LE32(block.size) - (sizeof(core) - sizeof(block)), SEEK_CUR);
963 }
964 else {
965 if (file->read(file, &core.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
966 }
967
968 if (core.major != LE16(1)) {
969 GB_log(gb, "This save state uses an incompatible version of the BESS specification");
970 GB_free(&save);
971 return -1;
972 }
973
974 switch (core.family) {
975 case 'C':
976 if (!GB_is_cgb(&save)) goto wrong_model;
977 break;
978 case 'S':
979 if (!GB_is_sgb(&save)) goto wrong_model;
980 break;
981 case 'G':
982 if (GB_is_cgb(&save) || GB_is_sgb(&save)) goto wrong_model;
983 break;
984 default:
985 wrong_model:
986 GB_log(gb, "The save state is for a different model. Try changing the emulated model.\n");
987 GB_free(&save);
988 return -1;
989 }
990
991
992 save.pc = LE16(core.pc);
993 save.af = LE16(core.af);
994 save.bc = LE16(core.bc);
995 save.de = LE16(core.de);
996 save.hl = LE16(core.hl);
997 save.sp = LE16(core.sp);
998
999 save.ime = core.ime;
1000 save.interrupt_enable = core.ie;
1001
1002 save.halted = core.execution_mode == 1;
1003 save.stopped = core.execution_mode == 2;
1004
1005 // Done early for compatibility with 0.14.x
1006 GB_write_memory(&save, 0xFF00 + GB_IO_SVBK, core.io_registers[GB_IO_SVBK]);
1007 // CPU related
1008
1009 // Determines DMG mode
1010 GB_write_memory(&save, 0xFF00 + GB_IO_KEY0, core.io_registers[GB_IO_KEY0]);
1011 save.boot_rom_finished = core.io_registers[GB_IO_BANK];
1012 GB_write_memory(&save, 0xFF00 + GB_IO_KEY1, core.io_registers[GB_IO_KEY1]);
1013 if (save.cgb_mode) {
1014 save.cgb_double_speed = core.io_registers[GB_IO_KEY1] & 0x80;
1015 save.object_priority = GB_OBJECT_PRIORITY_INDEX;
1016 }
1017 else {
1018 save.object_priority = GB_OBJECT_PRIORITY_X;
1019 }
1020
1021 // Timers, Joypad and Serial
1022 GB_write_memory(&save, 0xFF00 + GB_IO_JOYP, core.io_registers[GB_IO_JOYP]);
1023 GB_write_memory(&save, 0xFF00 + GB_IO_SB, core.io_registers[GB_IO_SB]);
1024 save.io_registers[GB_IO_SC] = core.io_registers[GB_IO_SC];
1025 save.div_counter = core.io_registers[GB_IO_DIV] << 8;
1026 GB_write_memory(&save, 0xFF00 + GB_IO_TIMA, core.io_registers[GB_IO_TIMA]);
1027 GB_write_memory(&save, 0xFF00 + GB_IO_TMA, core.io_registers[GB_IO_TMA]);
1028 GB_write_memory(&save, 0xFF00 + GB_IO_TAC, core.io_registers[GB_IO_TAC]);
1029
1030 // APU
1031 GB_write_memory(&save, 0xFF00 + GB_IO_NR52, core.io_registers[GB_IO_NR52]);
1032 for (unsigned i = GB_IO_NR10; i < GB_IO_NR52; i++) {
1033 uint8_t value = core.io_registers[i];
1034 if (i == GB_IO_NR14 || i == GB_IO_NR24 || i == GB_IO_NR34 || i == GB_IO_NR44) {
1035 value &= ~0x80;
1036 }
1037 GB_write_memory(&save, 0xFF00 + i, value);
1038 }
1039
1040 for (unsigned i = GB_IO_WAV_START; i <= GB_IO_WAV_END; i++) {
1041 GB_write_memory(&save, 0xFF00 + i, core.io_registers[i]);
1042 }
1043
1044 // PPU
1045 GB_write_memory(&save, 0xFF00 + GB_IO_LCDC, core.io_registers[GB_IO_LCDC]);
1046 GB_write_memory(&save, 0xFF00 + GB_IO_STAT, core.io_registers[GB_IO_STAT]);
1047 GB_write_memory(&save, 0xFF00 + GB_IO_SCY, core.io_registers[GB_IO_SCY]);
1048 GB_write_memory(&save, 0xFF00 + GB_IO_SCX, core.io_registers[GB_IO_SCX]);
1049 GB_write_memory(&save, 0xFF00 + GB_IO_LYC, core.io_registers[GB_IO_LYC]);
1050 save.io_registers[GB_IO_DMA] = core.io_registers[GB_IO_DMA];
1051 GB_write_memory(&save, 0xFF00 + GB_IO_BGP, core.io_registers[GB_IO_BGP]);
1052 GB_write_memory(&save, 0xFF00 + GB_IO_OBP0, core.io_registers[GB_IO_OBP0]);
1053 GB_write_memory(&save, 0xFF00 + GB_IO_OBP1, core.io_registers[GB_IO_OBP1]);
1054 GB_write_memory(&save, 0xFF00 + GB_IO_WX, core.io_registers[GB_IO_WX]);
1055 GB_write_memory(&save, 0xFF00 + GB_IO_WY, core.io_registers[GB_IO_WY]);
1056
1057 // Other registers
1058 GB_write_memory(&save, 0xFF00 + GB_IO_VBK, core.io_registers[GB_IO_VBK]);
1059 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA1, core.io_registers[GB_IO_HDMA1]);
1060 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA2, core.io_registers[GB_IO_HDMA2]);
1061 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA3, core.io_registers[GB_IO_HDMA3]);
1062 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA4, core.io_registers[GB_IO_HDMA4]);
1063 GB_write_memory(&save, 0xFF00 + GB_IO_RP, core.io_registers[GB_IO_RP]);
1064 GB_write_memory(&save, 0xFF00 + GB_IO_BGPI, core.io_registers[GB_IO_BGPI]);
1065 GB_write_memory(&save, 0xFF00 + GB_IO_OBPI, core.io_registers[GB_IO_OBPI]);
1066 GB_write_memory(&save, 0xFF00 + GB_IO_OPRI, core.io_registers[GB_IO_OPRI]);
1067
1068 // Interrupts
1069 GB_write_memory(&save, 0xFF00 + GB_IO_IF, core.io_registers[GB_IO_IF]);
1070
1071 /* Required to be compatible with both SameBoy 0.14.x AND BGB */
1072 if (GB_is_cgb(&save) && !save.cgb_mode && save.cgb_ram_bank == 7) {
1073 save.cgb_ram_bank = 1;
1074 }
1075
1076 break;
1077 case BE32('NAME'):
1078 if (LE32(block.size) > sizeof(emulator_name) - 1) {
1079 file->seek(file, LE32(block.size), SEEK_CUR);
1080 }
1081 else {
1082 file->read(file, emulator_name, LE32(block.size));
1083 }
1084 break;
1085 case BE32('INFO'): {
1086 BESS_INFO_t bess_info = {0,};
1087 if (LE32(block.size) != sizeof(bess_info) - sizeof(block)) goto parse_error;
1088 if (file->read(file, &bess_info.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1089 const uint8_t *bank = get_header_bank(gb);
1090 if (memcmp(bess_info.title, bank + 0x134, sizeof(bess_info.title))) {
1091 char ascii_title[0x11] = {0,};
1092 for (unsigned i = 0; i < 0x10; i++) {
1093 if (bess_info.title[i] < 0x20 || bess_info.title[i] > 0x7E) break;
1094 ascii_title[i] = bess_info.title[i];
1095 }
1096 GB_log(gb, "Save state was made on another ROM: '%s'\n", ascii_title);
1097 }
1098 else if (memcmp(bess_info.checksum, bank + 0x14E, 2)) {
1099 GB_log(gb, "Save state was potentially made on another revision of the same ROM.\n");
1100 }
1101 break;
1102 }
1103 case BE32('XOAM'):
1104 if (!found_core) goto parse_error;
1105 if (LE32(block.size) != 96) goto parse_error;
1106 file->read(file, save.extra_oam, sizeof(save.extra_oam));
1107 break;
1108 case BE32('MBC '):
1109 if (!found_core) goto parse_error;
1110 if (LE32(block.size) % 3 != 0) goto parse_error;
1111 if (LE32(block.size) > 0x1000) goto parse_error;
1112 /* Inject some default writes, as some emulators omit them */
1113 if (gb->cartridge_type->mbc_type == GB_MMM01) {
1114 GB_write_memory(&save, 0x6000, 0x30);
1115 GB_write_memory(&save, 0x4000, 0x70);
1116 }
1117 for (unsigned i = LE32(block.size); i > 0; i -= 3) {
1118 BESS_MBC_pair_t pair;
1119 file->read(file, &pair, sizeof(pair));
1120 if (LE16(pair.address) >= 0x8000 && LE16(pair.address) < 0xA000) goto parse_error;
1121 if (LE16(pair.address) >= 0xC000) goto parse_error;
1122 GB_write_memory(&save, LE16(pair.address), pair.value);
1123 }
1124 break;
1125 case BE32('RTC '):
1126 if (!found_core) goto parse_error;
1127 BESS_RTC_t bess_rtc;
1128 if (LE32(block.size) != sizeof(bess_rtc) - sizeof(block)) goto parse_error;
1129 if (file->read(file, &bess_rtc.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1130 if (!gb->cartridge_type->has_rtc || gb->cartridge_type->mbc_type != GB_MBC3) break;
1131 save.rtc_real.seconds = bess_rtc.real.seconds;
1132 save.rtc_real.minutes = bess_rtc.real.minutes;
1133 save.rtc_real.hours = bess_rtc.real.hours;
1134 save.rtc_real.days = bess_rtc.real.days;
1135 save.rtc_real.high = bess_rtc.real.high;
1136 save.rtc_latched.seconds = bess_rtc.latched.seconds;
1137 save.rtc_latched.minutes = bess_rtc.latched.minutes;
1138 save.rtc_latched.hours = bess_rtc.latched.hours;
1139 save.rtc_latched.days = bess_rtc.latched.days;
1140 save.rtc_latched.high = bess_rtc.latched.high;
1141 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
1142 save.last_rtc_second = MIN(LE64(bess_rtc.last_rtc_second), time(NULL));
1143 }
1144
1145 break;
1146 case BE32('HUC3'):
1147 if (!found_core) goto parse_error;
1148 BESS_HUC3_t bess_huc3;
1149 if (LE32(block.size) != sizeof(bess_huc3) - sizeof(block)) goto parse_error;
1150 if (file->read(file, &bess_huc3.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1151 if (gb->cartridge_type->mbc_type != GB_HUC3) break;
1152 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
1153 save.last_rtc_second = MIN(LE64(bess_huc3.data.last_rtc_second), time(NULL));
1154 }
1155 save.huc3.minutes = LE16(bess_huc3.data.minutes);
1156 save.huc3.days = LE16(bess_huc3.data.days);
1157 save.huc3.alarm_minutes = LE16(bess_huc3.data.alarm_minutes);
1158 save.huc3.alarm_days = LE16(bess_huc3.data.alarm_days);
1159 save.huc3.alarm_enabled = bess_huc3.data.alarm_enabled;
1160 break;
1161 case BE32('TPP1'):
1162 if (!found_core) goto parse_error;
1163 BESS_TPP1_t bess_tpp1;
1164 if (LE32(block.size) != sizeof(bess_tpp1) - sizeof(block)) goto parse_error;
1165 if (file->read(file, &bess_tpp1.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1166 if (gb->cartridge_type->mbc_type != GB_TPP1) break;
1167 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
1168 save.last_rtc_second = MIN(LE64(bess_tpp1.last_rtc_second), time(NULL));
1169 }
1170 unrolled for (unsigned i = 4; i--;) {
1171 save.rtc_real.data[i ^ 3] = bess_tpp1.real_rtc_data[i];
1172 save.rtc_latched.data[i ^ 3] = bess_tpp1.latched_rtc_data[i];
1173 }
1174 save.tpp1_mr4 = bess_tpp1.mr4;
1175 break;
1176 case BE32('MBC7'):
1177 if (!found_core) goto parse_error;
1178 BESS_MBC7_t bess_mbc7;
1179 if (LE32(block.size) != sizeof(bess_mbc7) - sizeof(block)) goto parse_error;
1180 if (file->read(file, &bess_mbc7.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1181 if (gb->cartridge_type->mbc_type != GB_MBC7) break;
1182
1183 save.mbc7.latch_ready = bess_mbc7.latch_ready;
1184 save.mbc7.eeprom_do = bess_mbc7.eeprom_do;
1185 save.mbc7.eeprom_di = bess_mbc7.eeprom_di;
1186 save.mbc7.eeprom_clk = bess_mbc7.eeprom_clk;
1187 save.mbc7.eeprom_cs = bess_mbc7.eeprom_cs;
1188 save.mbc7.eeprom_write_enabled = bess_mbc7.eeprom_write_enabled;
1189
1190 save.mbc7.argument_bits_left = bess_mbc7.argument_bits_left;
1191
1192 save.mbc7.eeprom_command = LE16(bess_mbc7.eeprom_command);
1193 save.mbc7.read_bits = LE16(bess_mbc7.read_bits);
1194
1195 save.mbc7.x_latch = LE16(bess_mbc7.x_latch);
1196 save.mbc7.y_latch = LE16(bess_mbc7.y_latch);
1197
1198 break;
1199 case BE32('SGB '):
1200 if (!found_core) goto parse_error;
1201 if (!gb->sgb) goto parse_error;
1202 if (LE32(block.size) > sizeof(sgb) - sizeof(block)) {
1203 if (file->read(file, &sgb.header + 1, sizeof(sgb) - sizeof(block)) != sizeof(sgb) - sizeof(block)) goto error;
1204 file->seek(file, LE32(block.size) - (sizeof(sgb) - sizeof(block)), SEEK_CUR);
1205 }
1206 else {
1207 if (file->read(file, &sgb.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
1208 }
1209 found_sgb = true;
1210 break;
1211 case BE32('END '):
1212 if (!found_core) goto parse_error;
1213 if (LE32(block.size) != 0) goto parse_error;
1214 goto done;
1215 default:
1216 file->seek(file, LE32(block.size), SEEK_CUR);
1217 break;
1218 }
1219 }
1220 done:
1221 save.mbc_ram_size = gb->mbc_ram_size;
1222 memcpy(gb, &save, GB_SECTION_OFFSET(unsaved));
1223 assert(GB_get_save_state_size(gb) == GB_get_save_state_size(&save));
1224 GB_free(&save);
1225 read_bess_buffer(&core.ram, file, gb->ram, gb->ram_size);
1226 read_bess_buffer(&core.vram, file, gb->vram, gb->vram_size);
1227 read_bess_buffer(&core.mbc_ram, file, gb->mbc_ram, gb->mbc_ram_size);
1228 read_bess_buffer(&core.oam, file, gb->oam, sizeof(gb->oam));
1229 read_bess_buffer(&core.hram, file, gb->hram, sizeof(gb->hram));
1230 read_bess_buffer(&core.background_palettes, file, gb->background_palettes_data, sizeof(gb->background_palettes_data));
1231 read_bess_buffer(&core.object_palettes, file, gb->object_palettes_data, sizeof(gb->object_palettes_data));
1232 if (gb->sgb) {
1233 memset(gb->sgb, 0, sizeof(*gb->sgb));
1234 GB_sgb_load_default_data(gb);
1235 if (gb->boot_rom_finished) {
1236 gb->sgb->intro_animation = GB_SGB_INTRO_ANIMATION_LENGTH;
1237 if (!found_sgb) {
1238 gb->sgb->disable_commands = true;
1239 }
1240 else {
1241 read_bess_buffer(&sgb.border_tiles, file, gb->sgb->border.tiles, sizeof(gb->sgb->border.tiles));
1242 read_bess_buffer(&sgb.border_tilemap, file, (void *)gb->sgb->border.map, sizeof(gb->sgb->border.map));
1243 read_bess_buffer(&sgb.border_palettes, file, (void *)gb->sgb->border.palette, sizeof(gb->sgb->border.palette));
1244
1245 read_bess_buffer(&sgb.active_palettes, file, (void *)gb->sgb->effective_palettes, sizeof(gb->sgb->effective_palettes));
1246 read_bess_buffer(&sgb.ram_palettes, file, (void *)gb->sgb->ram_palettes, sizeof(gb->sgb->ram_palettes));
1247 read_bess_buffer(&sgb.attribute_map, file, (void *)gb->sgb->attribute_map, sizeof(gb->sgb->attribute_map));
1248 read_bess_buffer(&sgb.attribute_files, file, (void *)gb->sgb->attribute_files, sizeof(gb->sgb->attribute_files));
1249
1250 gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] =
1251 gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0];
1252
1253 gb->sgb->player_count = sgb.multiplayer_state >> 4;
1254 gb->sgb->current_player = sgb.multiplayer_state & 0xF;
1255 if (gb->sgb->player_count > 4 || gb->sgb->player_count == 3 || gb->sgb->player_count == 0) {
1256 gb->sgb->player_count = 1;
1257 gb->sgb->current_player = 0;
1258 }
1259 }
1260 }
1261 else {
1262 // Effectively reset if didn't finish the boot ROM
1263 gb->pc = 0;
1264 }
1265 }
1266 if (emulator_name[0]) {
1267 GB_log(gb, "Save state imported from %s.\n", emulator_name);
1268 }
1269 else {
1270 GB_log(gb, "Save state imported from another emulator.\n"); // SameBoy always contains a NAME block
1271 }
1272 for (unsigned i = 0; i < 32; i++) {
1273 GB_palette_changed(gb, false, i * 2);
1274 GB_palette_changed(gb, true, i * 2);
1275 }
1276 gb->apu_output.sample_fraction = 0;
1277 return 0;
1278 parse_error:
1279 errno = -1;
1280 error:
1281 if (emulator_name[0]) {
1282 GB_log(gb, "Attempted to import a save state from %s, but the save state is invalid.\n", emulator_name);
1283 }
1284 else {
1285 GB_log(gb, "Attempted to import a save state from a different emulator or incompatible version, but the save state is invalid.\n");
1286 }
1287 GB_free(&save);
1288 sanitize_state(gb);
1289 return errno;
1290 }
1291
1292 static int load_state_internal(GB_gameboy_t *gb, virtual_file_t *file)
1293 {
1294 GB_gameboy_t save;
1295
1296 /* Every unread value should be kept the same. */
1297 memcpy(&save, gb, sizeof(save));
1298 /* ...Except ram size, we use it to detect old saves with incorrect ram sizes */
1299 save.ram_size = 0;
1300
1301
1302 if (file->read(file, GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) return errno;
1303 if (gb->magic != save.magic) {
1304 return load_bess_save(gb, file, false);
1305 }
1306 #define READ_SECTION(gb, file, section) read_section(file, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
1307 if (!READ_SECTION(&save, file, core_state)) return errno ?: EIO;
1308 if (!READ_SECTION(&save, file, dma )) return errno ?: EIO;
1309 if (!READ_SECTION(&save, file, mbc )) return errno ?: EIO;
1310 if (!READ_SECTION(&save, file, hram )) return errno ?: EIO;
1311 if (!READ_SECTION(&save, file, timing )) return errno ?: EIO;
1312 if (!READ_SECTION(&save, file, apu )) return errno ?: EIO;
1313 if (!READ_SECTION(&save, file, rtc )) return errno ?: EIO;
1314 if (!READ_SECTION(&save, file, video )) return errno ?: EIO;
1315 if (!READ_SECTION(&save, file, accessory )) return errno ?: EIO;
1316
1317
1318 bool attempt_bess = false;
1319 if (!verify_and_update_state_compatibility(gb, &save, &attempt_bess)) {
1320 if (attempt_bess) {
1321 return load_bess_save(gb, file, true);
1322 }
1323 return errno;
1324 }
1325
1326 if (GB_is_hle_sgb(gb)) {
1327 if (!read_section(file, gb->sgb, sizeof(*gb->sgb))) return errno ?: EIO;
1328 }
1329
1330 memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size);
1331 if (file->read(file, gb->mbc_ram, save.mbc_ram_size) != save.mbc_ram_size) {
1332 return errno ?: EIO;
1333 }
1334
1335 if (file->read(file, gb->ram, gb->ram_size) != gb->ram_size) {
1336 return errno ?: EIO;
1337 }
1338
1339 /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */
1340 file->seek(file, save.ram_size - gb->ram_size, SEEK_CUR);
1341
1342 if (file->read(file, gb->vram, gb->vram_size) != gb->vram_size) {
1343 return errno ?: EIO;
1344 }
1345
1346 uint32_t ram_size = gb->ram_size;
1347 uint32_t mbc_ram_size = gb->mbc_ram_size;
1348 memcpy(gb, &save, sizeof(save));
1349 gb->ram_size = ram_size;
1350 gb->mbc_ram_size = mbc_ram_size;
1351
1352 sanitize_state(gb);
1353 GB_rewind_invalidate_for_backstepping(gb);
1354 gb->apu_output.sample_fraction = 0;
1355 return 0;
1356 }
1357
1358 int GB_load_state(GB_gameboy_t *gb, const char *path)
1359 {
1360 GB_ASSERT_NOT_RUNNING(gb)
1361 FILE *f = fopen(path, "rb");
1362 if (!f) {
1363 GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
1364 return errno;
1365 }
1366 virtual_file_t file = {
1367 .read = file_read,
1368 .seek = file_seek,
1369 .tell = file_tell,
1370 .file = f,
1371 };
1372 int ret = load_state_internal(gb, &file);
1373 fclose(f);
1374 return ret;
1375 }
1376
1377 int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length)
1378 {
1379 GB_ASSERT_NOT_RUNNING(gb)
1380 virtual_file_t file = {
1381 .read = buffer_read,
1382 .seek = buffer_seek,
1383 .tell = buffer_tell,
1384 .buffer = (uint8_t *)buffer,
1385 .position = 0,
1386 .size = length,
1387 };
1388
1389 return load_state_internal(gb, &file);
1390 }
1391
1392 static int get_state_model_bess(virtual_file_t *file, GB_model_t *model)
1393 {
1394 file->seek(file, -sizeof(BESS_footer_t), SEEK_END);
1395 BESS_footer_t footer = {0, };
1396 file->read(file, &footer, sizeof(footer));
1397 if (footer.magic != BE32('BESS')) {
1398 return -1;
1399 }
1400
1401 file->seek(file, LE32(footer.start_offset), SEEK_SET);
1402 while (true) {
1403 BESS_block_t block;
1404 if (file->read(file, &block, sizeof(block)) != sizeof(block)) return errno;
1405 switch (block.magic) {
1406 case BE32('CORE'): {
1407 BESS_CORE_t core = {0,};
1408 if (LE32(block.size) > sizeof(core) - sizeof(block)) {
1409 if (file->read(file, &core.header + 1, sizeof(core) - sizeof(block)) != sizeof(core) - sizeof(block)) return errno;
1410 file->seek(file, LE32(block.size) - (sizeof(core) - sizeof(block)), SEEK_CUR);
1411 }
1412 else {
1413 if (file->read(file, &core.header + 1, LE32(block.size)) != LE32(block.size)) return errno;
1414 }
1415
1416 switch (core.full_model) {
1417 case BE32('GDB '): *model = GB_MODEL_DMG_B; return 0;
1418 case BE32('GM '): *model = GB_MODEL_MGB; return 0;
1419 case BE32('SN '): *model = GB_MODEL_SGB_NTSC_NO_SFC; return 0;
1420 case BE32('SP '): *model = GB_MODEL_SGB_PAL; return 0;
1421 case BE32('S2 '): *model = GB_MODEL_SGB2; return 0;
1422 case BE32('CC0 '): *model = GB_MODEL_CGB_0; return 0;
1423 case BE32('CCA '): *model = GB_MODEL_CGB_A; return 0;
1424 case BE32('CCB '): *model = GB_MODEL_CGB_B; return 0;
1425 case BE32('CCC '): *model = GB_MODEL_CGB_C; return 0;
1426 case BE32('CCD '): *model = GB_MODEL_CGB_D; return 0;
1427 case BE32('CCE '): *model = GB_MODEL_CGB_E; return 0;
1428 case BE32('CAA '): *model = GB_MODEL_AGB_A; return 0;
1429 }
1430 return -1;
1431
1432 default:
1433 file->seek(file, LE32(block.size), SEEK_CUR);
1434 break;
1435 }
1436 }
1437 }
1438 return -1;
1439 }
1440
1441
1442 static int get_state_model_internal(virtual_file_t *file, GB_model_t *model)
1443 {
1444 GB_gameboy_t save;
1445
1446
1447 if (file->read(file, GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) return errno;
1448 if (save.magic != GB_state_magic()) {
1449 return get_state_model_bess(file, model);
1450 }
1451 if (!READ_SECTION(&save, file, core_state)) return errno ?: EIO;
1452 *model = save.model;
1453 return 0;
1454 }
1455
1456 int GB_get_state_model(const char *path, GB_model_t *model)
1457 {
1458 FILE *f = fopen(path, "rb");
1459 if (!f) {
1460 return errno;
1461 }
1462 virtual_file_t file = {
1463 .read = file_read,
1464 .seek = file_seek,
1465 .tell = file_tell,
1466 .file = f,
1467 };
1468 int ret = get_state_model_internal(&file, model);
1469 fclose(f);
1470 return ret;
1471 }
1472
1473 int GB_get_state_model_from_buffer(const uint8_t *buffer, size_t length, GB_model_t *model)
1474 {
1475 virtual_file_t file = {
1476 .read = buffer_read,
1477 .seek = buffer_seek,
1478 .tell = buffer_tell,
1479 .buffer = (uint8_t *)buffer,
1480 .position = 0,
1481 .size = length,
1482 };
1483
1484 return get_state_model_internal(&file, model);
1485 }
1486
1487
1488 bool GB_is_save_state(const char *path)
1489 {
1490 bool ret = false;
1491 FILE *f = fopen(path, "rb");
1492 if (!f) return false;
1493 uint32_t magic = 0;
1494 fread(&magic, sizeof(magic), 1, f);
1495 if (magic == GB_state_magic()) {
1496 ret = true;
1497 goto exit;
1498 }
1499
1500 fseek(f, -sizeof(magic), SEEK_END);
1501 fread(&magic, sizeof(magic), 1, f);
1502 if (magic == BE32('BESS')) {
1503 ret = true;
1504 }
1505
1506 exit:
1507 fclose(f);
1508 return ret;
1509 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.