kolibrios/programs/emulator/dgen-sdl-1.33/save.cpp

463 lines
11 KiB
C++
Raw Normal View History

// DGen v1.10+
// Megadrive C++ module saving and loading
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "md.h"
#include "system.h"
void md::m68k_state_dump()
{
/*
32 and 16-bit values must be stored LSB first even though M68K is
big-endian for compatibility with other emulators.
*/
switch (cpu_emu) {
#ifdef WITH_MUSA
case CPU_EMU_MUSA:
if (md_set_musa(true))
md_set_musa_sync(false);
md_set_musa(false);
break;
#endif
#ifdef WITH_STAR
case CPU_EMU_STAR:
if (md_set_star(true))
md_set_star_sync(false);
md_set_star(false);
break;
#endif
#ifdef WITH_CYCLONE
case CPU_EMU_CYCLONE:
if (md_set_cyclone(true))
md_set_cyclone_sync(false);
md_set_cyclone(false);
break;
#endif
default:
break;
}
}
void md::m68k_state_restore()
{
/* 32 and 16-bit values are stored LSB first. */
switch (cpu_emu) {
#ifdef WITH_MUSA
case CPU_EMU_MUSA:
if (md_set_musa(true))
md_set_musa_sync(true);
md_set_musa(false);
break;
#endif
#ifdef WITH_STAR
case CPU_EMU_STAR:
if (md_set_star(true))
md_set_star_sync(true);
md_set_star(false);
break;
#endif
#ifdef WITH_CYCLONE
case CPU_EMU_CYCLONE:
if (md_set_cyclone(true))
md_set_cyclone_sync(true);
md_set_cyclone(false);
break;
#endif
default:
break;
}
}
void md::z80_state_dump()
{
/* 16-bit values must be stored LSB first. */
z80_state.irq_asserted = z80_st_irq;
z80_state.irq_vector = z80_irq_vector;
switch (z80_core) {
#ifdef WITH_CZ80
case Z80_CORE_CZ80:
if (md_set_cz80(true))
md_set_cz80_sync(false);
md_set_cz80(false);
break;
#endif
#ifdef WITH_MZ80
case Z80_CORE_MZ80:
if (md_set_mz80(true))
md_set_mz80_sync(false);
md_set_mz80(false);
break;
#endif
#ifdef WITH_DRZ80
case Z80_CORE_DRZ80:
if (md_set_drz80(true))
md_set_drz80_sync(false);
md_set_drz80(false);
break;
#endif
default:
break;
}
}
void md::z80_state_restore()
{
/* 16-bit values are stored LSB first. */
switch (z80_core) {
#ifdef WITH_CZ80
case Z80_CORE_CZ80:
if (md_set_cz80(true))
md_set_cz80_sync(true);
md_set_cz80(false);
break;
#endif
#ifdef WITH_MZ80
case Z80_CORE_MZ80:
if (md_set_mz80(true))
md_set_mz80_sync(true);
md_set_mz80(false);
break;
#endif
#ifdef WITH_DRZ80
case Z80_CORE_DRZ80:
if (md_set_drz80(true))
md_set_drz80_sync(true);
md_set_drz80(false);
break;
#endif
default:
break;
}
if (z80_state.irq_asserted)
z80_irq(z80_state.irq_vector);
else
z80_irq_clear();
}
/*
gs0 genecyst save file INfo
GST\0 to start with
80-9f = d0-d7 almost certain
a0-bf = a0-a7 almost certain
c8 = pc fairly certain
d0 = sr fairly certain
112 Start of cram len 0x80
192 Start of vsram len 0x50
1e2-474 UNKNOWN sound info?
Start of z80 ram at 474 (they store 2000)
Start of RAM at 2478 almost certain (BYTE SWAPPED)
Start of VRAM at 12478
end of VRAM
*/
/*
2011-11-05 - Adapted from Gens' genecyst_save_file_format.txt:
Range Size Description
----------- ----- -----------
00000-00002 3 "GST"
00003-00004 2 "\x40\xe0" (Gens and new DGen format)
00006-00007 2 "\xe0\x40" (old DGen format)
00040-00043 4 Last VDP control data written
00044-00044 1 Second write flag
00045-00045 1 DMA fill flag
00048-0004B 4 VDP write address
00050-00050 1 Version
00051-00051 1 Emulator ID
00052-00052 1 System ID
00060-0006F 16 PSG registers
00080-000D9 90 M68K registers
000FA-00111 24 VDP registers
00112-00191 128 Color RAM
00192-001E1 80 Vertical scroll RAM
001E2-001E2 1 YM2612 part I address register (DGen)
001E3-001E3 1 YM2612 part II address register (DGen)
001E4-003E3 512 YM2612 registers
00404-00437 52 Z80 registers
00438-0043F 8 Z80 state
00474-02473 8192 Z80 RAM
02478-12477 65536 68K RAM
12478-22477 65536 Video RAM
M68K registers (stored little-endian for compatibility)
--------------
00080-0009F : D0-D7
000A0-000BF : A0-A7
000C8 : PC
000D0 : SR
000D2 : USP
000D6 : SSP
Z80 registers (little-endian)
-------------
00404 : AF
00408 : BC
0040C : DE
00410 : HL
00414 : IX
00418 : IY
0041C : PC
00420 : SP
00424 : AF'
00428 : BC'
0042C : DE'
00430 : HL'
00434 : I
00435 : R (DGen)
00436 : x x x x x IFF1 x IFF2 (Gens v5)
00437 : IM (DGen)
Z80 State
---------
00438 : Z80 RESET
00439 : Z80 BUSREQ
0043A : Unknown
0043B : Unknown
0043C : Z80 BANK (DWORD)
Gens and Kega ADD
-----------------
00040 : last VDP Control data written (DWORD)
00044 : second write flag (1 for second write)
00045 : DMA Fill flag (1 mean next data write will cause a DMA fill)
00048 : VDP write address (DWORD)
00050 : Version (Genecyst=0; Kega=5; Gens=5; DGen=5)
00051 : Emulator ID (Genecyst=0; Kega=0; Gens=1; DGen=9)
00052 : System ID (Genesis=0; SegaCD=1; 32X=2; SegaCD32X=3)
00060-0007F : PSG registers (DWORDs, little endian).
*/
static void *swap16cpy(void *dest, const void *src, size_t n)
{
size_t i;
for (i = 0; (i != (n & ~1)); ++i)
((uint8_t *)dest)[(i ^ 1)] = ((uint8_t *)src)[i];
((uint8_t *)dest)[i] = ((uint8_t *)src)[i];
return dest;
}
int md::import_gst(FILE *hand)
{
uint8_t (*buf)[0x22478] =
(uint8_t (*)[sizeof(*buf)])malloc(sizeof(*buf));
uint8_t *p;
uint8_t *q;
size_t i;
uint32_t tmp;
if ((buf == NULL) ||
(fread((*buf), sizeof(*buf), 1, hand) != 1) ||
/* GST header */
((memcmp((*buf), "GST\x0\x0\0\xe0\x40", 8) != 0) &&
(memcmp((*buf), "GST\x40\xe0", 5) != 0))) {
fprintf(stderr,
"%s: error: invalid save file header.\n",
__func__);
free(buf);
return -1;
}
p = &(*buf)[0x50];
if (p[2] != 0) {
fprintf(stderr,
"%s: error: this is not a Genesis/Mega Drive"
" save file.\n",
__func__);
free(buf);
return -1;
}
if (p[1] != 9) {
fprintf(stderr,
"%s: warning: save file was probably not generated by"
" DGen/SDL.\n",
__func__);
}
else if (p[0] != 5)
fprintf(stderr,
"%s: warning: unknown save file version.\n",
__func__);
/* Reset console first. */
reset();
/* FIXME: VDP stuff */
/* PSG registers (8x16-bit, 16 bytes) */
SN76496_restore(0, &(*buf)[0x60]);
/* M68K registers (19x32-bit, 1x16-bit, 90 bytes (padding: 12)) */
p = &(*buf)[0x80];
q = &(*buf)[0xa0];
for (i = 0; (i != 8); ++i, p += 4, q += 4) {
memcpy(&m68k_state.d[i], p, 4);
memcpy(&m68k_state.a[i], q, 4);
}
memcpy(&m68k_state.pc, &(*buf)[0xc8], 4);
memcpy(&m68k_state.sr, &(*buf)[0xd0], 2);
/*
FIXME?
memcpy(&m68k_state.usp, &(*buf)[0xd2], 4);
memcpy(&m68k_state.ssp, &(*buf)[0xd6], 4);
*/
m68k_state_restore();
/* VDP registers (24x8-bit VDP registers, not sizeof(vdp.reg)) */
memcpy(vdp.reg, &(*buf)[0xfa], 0x18);
memset(&vdp.reg[0x18], 0, (sizeof(vdp.reg) - 0x18));
/* CRAM (64x16-bit registers, 128 bytes), swapped */
swap16cpy(vdp.cram, &(*buf)[0x112], 0x80);
/* VSRAM (40x16-bit words, 80 bytes), swapped */
swap16cpy(vdp.vsram, &(*buf)[0x192], 0x50);
/* YM2612 registers */
p = &(*buf)[0x1e2];
fm_sel[0] = p[0];
fm_sel[1] = p[1];
p = &(*buf)[0x1e4];
YM2612_restore(0, p);
fm_reg[0][0x24] = p[0x24];
fm_reg[0][0x25] = p[0x25];
fm_reg[0][0x26] = p[0x26];
fm_reg[0][0x27] = p[0x27];
dac_data[0] = p[0x2a];
dac_enabled = (p[0x2b] >> 7);
memset(fm_ticker, 0, sizeof(fm_ticker));
/* Z80 registers (12x16-bit and 4x8-bit, 52 bytes (padding: 24)) */
p = &(*buf)[0x404];
for (i = 0; (i != 2); ++i, p = &(*buf)[0x424]) {
memcpy(&z80_state.alt[i].fa, &p[0x0], 2);
memcpy(&z80_state.alt[i].cb, &p[0x4], 2);
memcpy(&z80_state.alt[i].ed, &p[0x8], 2);
memcpy(&z80_state.alt[i].lh, &p[0xc], 2);
}
p = &(*buf)[0x414];
memcpy(&z80_state.ix, &p[0x0], 2);
memcpy(&z80_state.iy, &p[0x4], 2);
memcpy(&z80_state.pc, &p[0x8], 2);
memcpy(&z80_state.sp, &p[0xc], 2);
p = &(*buf)[0x434];
z80_state.i = p[0];
z80_state.r = p[1];
z80_state.iff = ((p[2] << 1) | p[2]); /* IFF2 = IFF1 */
z80_state.im = ((p[3] == 0) ? 1 : p[3]);
z80_state_restore();
/* Z80 state (8 bytes) */
p = &(*buf)[0x438];
z80_st_reset = !p[0]; /* BUS RESET state */
if (z80_st_reset) {
z80_reset();
fm_reset();
}
z80_st_busreq = (p[1] & 1); /* BUSREQ state */
memcpy(&tmp, &(*buf)[0x43c], 4);
z80_bank68k = le2h32(tmp);
/* Z80 RAM (8192 bytes) */
memcpy(z80ram, &(*buf)[0x474], 0x2000);
/* RAM (65536 bytes), swapped */
swap16cpy(ram, &(*buf)[0x2478], 0x10000);
/* VRAM (65536 bytes) */
memcpy(vdp.vram, &(*buf)[0x12478], 0x10000);
/* Mark everything as changed */
memset(vdp.dirt, 0xff, 0x35);
free(buf);
return 0;
}
int md::export_gst(FILE *hand)
{
uint8_t (*buf)[0x22478] =
(uint8_t (*)[sizeof(*buf)])calloc(1, sizeof(*buf));
uint8_t *p;
uint8_t *q;
size_t i;
uint32_t tmp;
if (buf == NULL)
return -1;
/* GST header */
memcpy((*buf), "GST\x40\xe0", 5);
/* FIXME: VDP stuff */
/* Version */
(*buf)[0x50] = 5;
/* Emulator ID */
(*buf)[0x51] = 9;
/* System ID */
(*buf)[0x52] = 0;
/* PSG registers (8x16-bit, 16 bytes) */
SN76496_dump(0, &(*buf)[0x60]);
/* M68K registers (19x32-bit, 1x16-bit, 90 bytes (padding: 12)) */
m68k_state_dump();
p = &(*buf)[0x80];
q = &(*buf)[0xa0];
for (i = 0; (i != 8); ++i, p += 4, q += 4) {
memcpy(p, &m68k_state.d[i], 4);
memcpy(q, &m68k_state.a[i], 4);
}
memcpy(&(*buf)[0xc8], &m68k_state.pc, 4);
memcpy(&(*buf)[0xd0], &m68k_state.sr, 2);
/*
FIXME?
memcpy(&(*buf)[0xd2], &m68k_state.usp, 4);
memcpy(&(*buf)[0xd6], &m68k_state.ssp, 4);
*/
/* VDP registers (24x8-bit VDP registers, not sizeof(vdp.reg)) */
memcpy(&(*buf)[0xfa], vdp.reg, 0x18);
/* CRAM (64x16-bit registers, 128 bytes), swapped */
swap16cpy(&(*buf)[0x112], vdp.cram, 0x80);
/* VSRAM (40x16-bit words, 80 bytes), swapped */
swap16cpy(&(*buf)[0x192], vdp.vsram, 0x50);
/* YM2612 registers */
p = &(*buf)[0x1e2];
p[0] = fm_sel[0];
p[1] = fm_sel[1];
p = &(*buf)[0x1e4];
YM2612_dump(0, p);
p[0x24] = fm_reg[0][0x24];
p[0x25] = fm_reg[0][0x25];
p[0x26] = fm_reg[0][0x26];
p[0x27] = fm_reg[0][0x27];
p[0x2a] = 0xff;
p[0x2b] = (dac_enabled << 7);
/* Z80 registers (12x16-bit and 4x8-bit, 52 bytes (padding: 24)) */
z80_state_dump();
p = &(*buf)[0x404];
for (i = 0; (i != 2); ++i, p = &(*buf)[0x424]) {
memcpy(&p[0x0], &z80_state.alt[i].fa, 2);
memcpy(&p[0x4], &z80_state.alt[i].cb, 2);
memcpy(&p[0x8], &z80_state.alt[i].ed, 2);
memcpy(&p[0xc], &z80_state.alt[i].lh, 2);
}
p = &(*buf)[0x414];
memcpy(&p[0x0], &z80_state.ix, 2);
memcpy(&p[0x4], &z80_state.iy, 2);
memcpy(&p[0x8], &z80_state.pc, 2);
memcpy(&p[0xc], &z80_state.sp, 2);
p = &(*buf)[0x434];
p[0] = z80_state.i;
p[1] = z80_state.r;
p[2] = ((z80_state.iff >> 1) | z80_state.iff);
p[3] = z80_state.im;
/* Z80 state (8 bytes) */
p = &(*buf)[0x438];
p[0] = !z80_st_reset;
p[1] = z80_st_busreq;
tmp = h2le32(z80_bank68k);
memcpy(&(*buf)[0x43c], &tmp, 4);
/* Z80 RAM (8192 bytes) */
memcpy(&(*buf)[0x474], z80ram, 0x2000);
/* RAM (65536 bytes), swapped */
swap16cpy(&(*buf)[0x2478], ram, 0x10000);
/* VRAM (65536 bytes) */
memcpy(&(*buf)[0x12478], vdp.vram, 0x10000);
/* Output */
i = fwrite((*buf), sizeof(*buf), 1, hand);
free(buf);
if (i != 1)
return -1;
return 0;
}