32x and sms savestates. Core-independent z80 state. SS bugfixing/refactoring.

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@868 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2010-01-27 16:30:41 +00:00
parent a736af3ecf
commit b4db550e41
19 changed files with 1116 additions and 848 deletions

View file

@ -352,7 +352,7 @@ static void p32x_vdp_write8(u32 a, u32 d)
Pico32x.pending_fb = d;
// if we are blanking and FS bit is changing
if (((r[0x0a/2] & P32XV_VBLK) || (r[0] & P32XV_Mx) == 0) && ((r[0x0a/2] ^ d) & P32XV_FS)) {
r[0x0a/2] ^= 1;
r[0x0a/2] ^= P32XV_FS;
Pico32xSwapDRAM(d ^ 1);
elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
}
@ -1329,7 +1329,7 @@ static void get_bios(void)
// M68K ROM
if (p32x_bios_g != NULL) {
elprintf(EL_STATUS|EL_32X, "32x: using supplied 68k BIOS");
Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, 0x100);
Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, sizeof(Pico32xMem->m68k_rom));
}
else {
// generate 68k ROM
@ -1351,7 +1351,9 @@ static void get_bios(void)
#endif
}
// fill remaining m68k_rom page with game ROM
memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
memcpy(Pico32xMem->m68k_rom_bank + sizeof(Pico32xMem->m68k_rom),
Pico.rom + sizeof(Pico32xMem->m68k_rom),
sizeof(Pico32xMem->m68k_rom_bank) - sizeof(Pico32xMem->m68k_rom));
// MSH2
if (p32x_bios_m != NULL) {
@ -1439,9 +1441,9 @@ void PicoMemSetup32x(void)
// m68k_map_unmap(0x000000, 0x3fffff);
// MD ROM area
rs = sizeof(Pico32xMem->m68k_rom);
cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
rs = sizeof(Pico32xMem->m68k_rom_bank);
cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom_bank, 0);
cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico32xMem->m68k_rom_bank, 0);
cpu68k_map_set(m68k_write8_map, 0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
@ -1538,4 +1540,16 @@ void PicoMemSetup32x(void)
#endif
}
void Pico32xStateLoaded(void)
{
bank_switch(Pico32x.regs[4 / 2]);
Pico32xSwapDRAM((Pico32x.vdp_regs[0x0a / 2] & P32XV_FS) ^ P32XV_FS);
p32x_poll_event(3, 0);
Pico32x.dirty_pal = 1;
memset(Pico32xMem->pwm, 0, sizeof(Pico32xMem->pwm));
#ifdef DRC_SH2
sh2_drc_flush_all();
#endif
}
// vim:shiftwidth=2:expandtab

View file

@ -145,7 +145,6 @@ void p32x_pwm_write16(unsigned int a, unsigned int d)
void p32x_pwm_update(int *buf32, int length, int stereo)
{
extern int pwm_ptr;
short *pwmb;
int step;
int p = 0;

View file

@ -1,300 +0,0 @@
// This is part of Pico Library
// (c) Copyright 2004 Dave, All rights reserved.
// (c) Copyright 2006 notaz, All rights reserved.
// Free for non-commercial use.
// For commercial use, separate licencing terms must be obtained.
#include "pico_int.h"
#include <zlib/zlib.h>
// ym2612
#include "sound/ym2612.h"
// sn76496
extern int *sn76496_regs;
struct PicoArea { void *data; int len; char *name; };
// strange observation on Symbian OS 9.1, m600 organizer fw r3a06:
// taking an address of fread or fwrite causes "application could't be started" error
// on startup randomly depending on binary layout of executable file.
arearw *areaRead = (arearw *) 0; // fread; // read and write function pointers for
arearw *areaWrite = (arearw *) 0; // fwrite; // gzip save state ability
areaeof *areaEof = (areaeof *) 0;
areaseek *areaSeek = (areaseek *) 0;
areaclose *areaClose = (areaclose *) 0;
void (*PicoLoadStateHook)(void) = NULL;
// Scan one variable and callback
static int ScanVar(void *data,int len,char *name,void *PmovFile,int is_write)
{
int ret = 0;
if (is_write)
ret = areaWrite(data,1,len,PmovFile);
else
ret = areaRead (data,1,len,PmovFile);
return (ret != len);
}
#define SCAN_VAR(x,y) ScanVar(&x,sizeof(x),y,PmovFile,is_write);
#define SCANP(x) ScanVar(&Pico.x,sizeof(Pico.x),#x,PmovFile,is_write);
// Pack the cpu into a common format:
PICO_INTERNAL void PicoAreaPackCpu(unsigned char *cpu, int is_sub)
{
unsigned int pc=0;
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
memcpy(cpu,context->d,0x40);
pc=context->pc-context->membase;
*(unsigned int *)(cpu+0x44)=CycloneGetSr(context);
*(unsigned int *)(cpu+0x48)=context->osp;
cpu[0x4c] = context->irq;
cpu[0x4d] = context->state_flags & 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
memcpy(cpu,m68ki_cpu_p->dar,0x40);
pc=m68ki_cpu_p->pc;
*(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
*(unsigned int *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
cpu[0x4c] = CPU_INT_LEVEL>>8;
cpu[0x4d] = CPU_STOPPED;
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(cpu,context->dreg,0x40);
pc=context->pc;
*(unsigned int *)(cpu+0x44)=context->sr;
*(unsigned int *)(cpu+0x48)=context->asp;
cpu[0x4c] = context->interrupts[0];
cpu[0x4d] = (context->execinfo & FM68K_HALTED) ? 1 : 0;
#endif
*(unsigned int *)(cpu+0x40)=pc;
}
PICO_INTERNAL void PicoAreaUnpackCpu(unsigned char *cpu, int is_sub)
{
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
CycloneSetSr(context, *(unsigned int *)(cpu+0x44));
context->osp=*(unsigned int *)(cpu+0x48);
memcpy(context->d,cpu,0x40);
context->membase = 0;
context->pc = *(unsigned int *)(cpu+0x40);
CycloneUnpack(context, NULL); // rebase PC
context->irq = cpu[0x4c];
context->state_flags = 0;
if (cpu[0x4d])
context->state_flags |= 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
memcpy(m68ki_cpu_p->dar,cpu,0x40);
m68ki_cpu_p->pc=*(unsigned int *)(cpu+0x40);
m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(unsigned int *)(cpu+0x48);
CPU_INT_LEVEL = cpu[0x4c] << 8;
CPU_STOPPED = cpu[0x4d];
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(context->dreg,cpu,0x40);
context->pc =*(unsigned int *)(cpu+0x40);
context->sr =*(unsigned int *)(cpu+0x44);
context->asp=*(unsigned int *)(cpu+0x48);
context->interrupts[0] = cpu[0x4c];
context->execinfo &= ~FM68K_HALTED;
if (cpu[0x4d]&1) context->execinfo |= FM68K_HALTED;
#endif
}
// Scan the contents of the virtual machine's memory for saving or loading
static int PicoAreaScan(int is_write, unsigned int ver, void *PmovFile)
{
void *ym2612_regs;
unsigned char cpu[0x60];
unsigned char cpu_z80[0x60];
int ret;
memset(&cpu,0,sizeof(cpu));
memset(&cpu_z80,0,sizeof(cpu_z80));
Pico.m.scanline=0;
ym2612_regs = YM2612GetRegs();
// Scan all the memory areas:
SCANP(ram) SCANP(vram) SCANP(zram) SCANP(cram) SCANP(vsram)
// Pack, scan and unpack the cpu data:
if (is_write)
PicoAreaPackCpu(cpu, 0);
SCAN_VAR(cpu,"cpu")
if (!is_write)
PicoAreaUnpackCpu(cpu, 0);
SCAN_VAR(Pico.m ,"misc")
SCAN_VAR(Pico.video,"video")
// no longer keeping eeprom data in sram_reg
if (!is_write && (Pico.m.sram_reg & 4))
Pico.m.sram_reg = SRR_MAPPED;
if (is_write)
z80_pack(cpu_z80);
ret = SCAN_VAR(cpu_z80,"cpu_z80")
// do not unpack if we fail to load z80 state
if (!is_write) {
if (ret) z80_reset();
else z80_unpack(cpu_z80);
}
ScanVar(sn76496_regs, 28*4, "SN76496state", PmovFile, is_write);
if (is_write)
ym2612_pack_state();
ret = ScanVar(ym2612_regs, 0x200+4, "YM2612state", PmovFile, is_write); // regs + addr line
if (!is_write && !ret)
ym2612_unpack_state();
return 0;
}
// ---------------------------------------------------------------------------
// Helper code to save/load to a file handle
// XXX: error checking
// Save or load the state from PmovFile:
static int PmovState(int is_write, void *PmovFile)
{
unsigned char head[32];
if ((PicoAHW & PAHW_MCD) || carthw_chunks != NULL)
{
if (is_write)
return PicoCdSaveState(PmovFile);
else {
int ret = PicoCdLoadState(PmovFile);
if (PicoLoadStateHook) PicoLoadStateHook();
return ret;
}
}
memset(head,0,sizeof(head));
// not really used..
memcpy(head,"Pico",4);
*(unsigned int *)(head+0x8)=0x0133;
*(unsigned int *)(head+0xc)=0x0021;
// Scan header:
if (is_write)
areaWrite(head,1,sizeof(head),PmovFile);
else
areaRead (head,1,sizeof(head),PmovFile);
// Scan memory areas:
PicoAreaScan(is_write, *(unsigned int *)(head+0x8), PmovFile);
if (!is_write && PicoLoadStateHook)
PicoLoadStateHook();
return 0;
}
static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)
{
return gzread(file, p, _n);
}
static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)
{
return gzwrite(file, p, _n);
}
static void set_cbs(int gz)
{
if (gz) {
areaRead = gzRead2;
areaWrite = gzWrite2;
areaEof = (areaeof *) gzeof;
areaSeek = (areaseek *) gzseek;
areaClose = (areaclose *) gzclose;
} else {
areaRead = (arearw *) fread;
areaWrite = (arearw *) fwrite;
areaEof = (areaeof *) feof;
areaSeek = (areaseek *) fseek;
areaClose = (areaclose *) fclose;
}
}
int PicoState(const char *fname, int is_save)
{
void *afile = NULL;
int ret;
if (strcmp(fname + strlen(fname) - 3, ".gz") == 0)
{
if ( (afile = gzopen(fname, is_save ? "wb" : "rb")) ) {
set_cbs(1);
if (is_save)
gzsetparams(afile, 9, Z_DEFAULT_STRATEGY);
}
}
else
{
if ( (afile = fopen(fname, is_save ? "wb" : "rb")) ) {
set_cbs(0);
}
}
if (afile == NULL)
return -1;
ret = PmovState(is_save, afile);
areaClose(afile);
if (!is_save)
Pico.m.dirtyPal=1;
return ret;
}
int PicoStateLoadVDP(const char *fname)
{
void *afile = NULL;
if (strcmp(fname + strlen(fname) - 3, ".gz") == 0)
{
if ( (afile = gzopen(fname, "rb")) )
set_cbs(1);
}
else
{
if ( (afile = fopen(fname, "rb")) )
set_cbs(0);
}
if (afile == NULL)
return -1;
if ((PicoAHW & PAHW_MCD) || carthw_chunks != NULL) {
PicoCdLoadStateGfx(afile);
} else {
areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM in state file
areaRead(Pico.vram, 1, sizeof(Pico.vram), afile);
areaSeek(afile, 0x2000, SEEK_CUR);
areaRead(Pico.cram, 1, sizeof(Pico.cram), afile);
areaRead(Pico.vsram, 1, sizeof(Pico.vsram), afile);
areaSeek(afile, 0x221a0, SEEK_SET);
areaRead(&Pico.video, 1, sizeof(Pico.video), afile);
}
areaClose(afile);
return 0;
}

View file

@ -439,6 +439,9 @@ static unsigned char *PicoCartAlloc(int filesize, int is_sms)
if (filesize > (1 << s))
s++;
rom_alloc_size = 1 << s;
// be sure we can cover all address space
if (rom_alloc_size < 0x10000)
rom_alloc_size = 0x10000;
}
else {
// make alloc size at least sizeof(mcd_state),

View file

@ -1,321 +0,0 @@
// Savestate handling for emulated Sega/Mega CD machine.
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
#include "../pico_int.h"
// ym2612
#include "../sound/ym2612.h"
// sn76496
extern int *sn76496_regs;
carthw_state_chunk *carthw_chunks;
void (*PicoStateProgressCB)(const char *str) = 0;
typedef enum {
CHUNK_M68K = 1,
CHUNK_RAM,
CHUNK_VRAM,
CHUNK_ZRAM,
CHUNK_CRAM, // 5
CHUNK_VSRAM,
CHUNK_MISC,
CHUNK_VIDEO,
CHUNK_Z80,
CHUNK_PSG, // 10
CHUNK_FM,
// CD stuff
CHUNK_S68K,
CHUNK_PRG_RAM,
CHUNK_WORD_RAM,
CHUNK_PCM_RAM, // 15
CHUNK_BRAM,
CHUNK_GA_REGS,
CHUNK_PCM,
CHUNK_CDC,
CHUNK_CDD, // 20
CHUNK_SCD,
CHUNK_RC,
CHUNK_MISC_CD,
CHUNK_DEFAULT_COUNT
// CHUNK_CARTHW = 64, // defined in PicoInt
} chunk_name_e;
static char *chunk_names[] = {
"INVALID!",
"Saving.. M68K state",
"Saving.. RAM",
"Saving.. VRAM",
"Saving.. ZRAM",
"Saving.. CRAM", // 5
"Saving.. VSRAM",
"Saving.. emu state",
"Saving.. VIDEO",
"Saving.. Z80 state",
"Saving.. PSG", // 10
"Saving.. FM",
// CD stuff
"Saving.. S68K state",
"Saving.. PRG_RAM",
"Saving.. WORD_RAM",
"Saving.. PCM_RAM", // 15
"Saving.. BRAM",
"Saving.. GATE ARRAY regs",
"Saving.. PCM state",
"Saving.. CDC",
"Saving.. CDD", // 20
"Saving.. SCD",
"Saving.. GFX chip",
"Saving.. MCD state",
};
static int write_chunk(chunk_name_e name, int len, void *data, void *file)
{
size_t bwritten = 0;
bwritten += areaWrite(&name, 1, 1, file);
bwritten += areaWrite(&len, 1, 4, file);
bwritten += areaWrite(data, 1, len, file);
return (bwritten == len + 4 + 1);
}
#define CHECKED_WRITE(name,len,data) { \
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) \
PicoStateProgressCB(chunk_names[name]); \
if (!write_chunk(name, len, data, file)) return 1; \
}
#define CHECKED_WRITE_BUFF(name,buff) { \
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) \
PicoStateProgressCB(chunk_names[name]); \
if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \
}
PICO_INTERNAL int PicoCdSaveState(void *file)
{
unsigned char buff[0x60];
void *ym2612_regs = YM2612GetRegs();
int ver = 0x0133; // not really used..
areaWrite("PicoSEXT", 1, 8, file);
areaWrite(&ver, 1, 4, file);
memset(buff, 0, sizeof(buff));
PicoAreaPackCpu(buff, 0);
CHECKED_WRITE_BUFF(CHUNK_M68K, buff);
CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);
CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);
CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);
CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);
CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);
CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);
CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);
memset(buff, 0, sizeof(buff));
z80_pack(buff);
CHECKED_WRITE_BUFF(CHUNK_Z80, buff);
CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);
ym2612_pack_state();
CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);
if (PicoAHW & PAHW_MCD)
{
memset(buff, 0, sizeof(buff));
PicoAreaPackCpu(buff, 1);
if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
wram_1M_to_2M(Pico_mcd->word_ram2M);
Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);
CHECKED_WRITE_BUFF(CHUNK_S68K, buff);
CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);
CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format
CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);
CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);
CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs
CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);
CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);
CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);
CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);
CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);
CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);
if (Pico_mcd->s68k_regs[3]&4) // convert back
wram_2M_to_1M(Pico_mcd->word_ram2M);
}
if (carthw_chunks != NULL)
{
carthw_state_chunk *chwc;
if (PicoStateProgressCB)
PicoStateProgressCB("Saving.. cart hw state");
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)
CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);
}
return 0;
}
static int g_read_offs = 0;
#define R_ERROR_RETURN(error) \
{ \
elprintf(EL_STATUS, "PicoCdLoadState @ %x: " error, g_read_offs); \
return 1; \
}
// when is eof really set?
#define CHECKED_READ(len,data) \
if (areaRead(data, 1, len, file) != len) { \
if (len == 1 && areaEof(file)) goto readend; \
R_ERROR_RETURN("areaRead: premature EOF\n"); \
return 1; \
} \
g_read_offs += len;
#define CHECKED_READ2(len2,data) \
if (len2 != len) { \
elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \
if (len > len2) R_ERROR_RETURN("failed."); \
/* else read anyway and hope for the best.. */ \
} \
CHECKED_READ(len, data)
#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);
PICO_INTERNAL int PicoCdLoadState(void *file)
{
unsigned char buff[0x60], buff_m68k[0x60], buff_s68k[0x60];
int ver, len;
void *ym2612_regs = YM2612GetRegs();
g_read_offs = 0;
CHECKED_READ(8, buff);
if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))
R_ERROR_RETURN("bad header");
CHECKED_READ(4, &ver);
while (!areaEof(file))
{
CHECKED_READ(1, buff);
CHECKED_READ(4, &len);
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
R_ERROR_RETURN("cd chunk in non CD state?");
switch (buff[0])
{
case CHUNK_M68K:
CHECKED_READ_BUFF(buff_m68k);
break;
case CHUNK_Z80:
CHECKED_READ_BUFF(buff);
z80_unpack(buff);
break;
case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;
case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;
case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;
case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;
case CHUNK_FM:
CHECKED_READ2(0x200+4, ym2612_regs);
ym2612_unpack_state();
break;
// cd stuff
case CHUNK_S68K:
CHECKED_READ_BUFF(buff_s68k);
break;
case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;
case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;
case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;
case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;
case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;
case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;
case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;
case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;
case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;
case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;
case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;
default:
if (carthw_chunks != NULL)
{
carthw_state_chunk *chwc;
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {
if (chwc->chunk == buff[0]) {
CHECKED_READ2(chwc->size, chwc->ptr);
goto breakswitch;
}
}
}
elprintf(EL_STATUS, "PicoCdLoadState: skipping unknown chunk %i of size %i", buff[0], len);
areaSeek(file, len, SEEK_CUR);
break;
}
breakswitch:;
}
readend:
if (PicoAHW & PAHW_MCD)
{
PicoMemStateLoaded();
if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))
cdda_start_play();
// must unpack after other CD stuff is loaded
PicoAreaUnpackCpu(buff_s68k, 1);
}
PicoAreaUnpackCpu(buff_m68k, 0);
return 0;
}
int PicoCdLoadStateGfx(void *file)
{
int ver, len, found = 0;
char buff[8];
g_read_offs = 0;
CHECKED_READ(8, buff);
if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))
R_ERROR_RETURN("bad header");
CHECKED_READ(4, &ver);
while (!areaEof(file) && found < 4)
{
CHECKED_READ(1, buff);
CHECKED_READ(4, &len);
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
R_ERROR_RETURN("cd chunk in non CD state?");
switch (buff[0])
{
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;
default:
areaSeek(file, len, SEEK_CUR);
break;
}
}
readend:
return 0;
}

View file

@ -322,7 +322,7 @@ static u32 PicoRead8_sram(u32 a)
static u32 PicoRead16_sram(u32 a)
{
u32 d;
if (SRam.end >= a && a >= SRam.start && (Pico.m.sram_reg & SRR_MAPPED))
if (SRam.start <= a && a <= SRam.end && (Pico.m.sram_reg & SRR_MAPPED))
{
if (SRam.flags & SRF_EEPROM)
d = EEPROM_read();

View file

@ -27,7 +27,7 @@ PicoRead8_sram: @ u32 a, u32 d
ldr r3, =(Pico+0x22200)
ldr r1, [r2, #8] @ SRam.end
cmp r0, r1
bge m_read8_nosram
bgt m_read8_nosram
ldr r1, [r2, #4] @ SRam.start
cmp r0, r1
blt m_read8_nosram
@ -58,8 +58,8 @@ m_read8_nosram:
m_read8_eeprom:
stmfd sp!,{r0,lr}
bl EEPROM_read
ldmfd sp!,{r0,lr}
tst r0, #1
ldmfd sp!,{r1,lr}
tst r1, #1
moveq r0, r0, lsr #8
bx lr
@ -126,7 +126,7 @@ PicoRead16_sram: @ u32 a, u32 d
ldr r3, =(Pico+0x22200)
ldr r1, [r2, #8] @ SRam.end
cmp r0, r1
bge m_read16_nosram
bgt m_read16_nosram
ldr r1, [r2, #4] @ SRam.start
cmp r0, r1
blt m_read16_nosram

View file

@ -34,6 +34,7 @@ extern void cache_flush_d_inval_i(const void *start_addr, const void *end_addr);
// attempt to alloc mem at specified address.
// alloc anywhere else if that fails (callers should handle that)
extern void *plat_mmap(unsigned long addr, size_t size);
extern void *plat_mremap(void *ptr, size_t oldsize, size_t newsize);
extern void plat_munmap(void *ptr, size_t size);
// this one should handle display mode changes
@ -119,12 +120,11 @@ extern picohw_state PicoPicohw;
// area.c
int PicoState(const char *fname, int is_save);
int PicoStateLoadVDP(const char *fname);
int PicoStateLoadGfx(const char *fname);
void *PicoTmpStateSave(void);
void PicoTmpStateRestore(void *data);
extern void (*PicoStateProgressCB)(const char *str);
// cd/area.c
int PicoCdLoadStateGfx(void *file);
// cd/buffering.c
void PicoCDBufferInit(void);
void PicoCDBufferFree(void);

View file

@ -178,14 +178,7 @@ extern int dbg_irq_level;
// ----------------------- Z80 CPU -----------------------
#if defined(_USE_MZ80)
#include "../cpu/mz80/mz80.h"
#define z80_run(cycles) { mz80GetElapsedTicks(1); mz80_run(cycles) }
#define z80_run_nr(cycles) mz80_run(cycles)
#define z80_int() mz80int(0)
#elif defined(_USE_DRZ80)
#if defined(_USE_DRZ80)
#include "../cpu/DrZ80/drz80.h"
extern struct DrZ80 drZ80;
@ -215,6 +208,8 @@ extern struct DrZ80 drZ80;
#endif
#define Z80_STATE_SIZE 0x60
extern int z80stopCycle; /* in 68k cycles */
extern int z80_cycle_cnt; /* 'done' z80 cycles before z80_run() */
extern int z80_cycle_aim;
@ -305,6 +300,13 @@ struct PicoMisc
unsigned int frame_count; // 1c for movies and idle det
};
struct PicoMS
{
unsigned char carthw[0x10];
unsigned char io_ctl;
unsigned char pad[0x4f];
};
// some assembly stuff depend on these, do not touch!
struct Pico
{
@ -314,9 +316,8 @@ struct Pico
unsigned char vramb[0x4000]; // VRAM in SMS mode
};
unsigned char zram[0x2000]; // 0x20000 Z80 ram
unsigned char ioports[0x10];
unsigned char sms_io_ctl;
unsigned char pad[0xef]; // unused
unsigned char ioports[0x10]; // XXX: fix asm and mv
unsigned char pad[0xf0]; // unused
unsigned short cram[0x40]; // 0x22100
unsigned short vsram[0x40]; // 0x22180
@ -325,6 +326,7 @@ struct Pico
struct PicoMisc m;
struct PicoVideo video;
struct PicoMS ms;
};
// sram
@ -487,6 +489,7 @@ struct Pico32x
unsigned short dmac_fifo[DMAC_FIFO_LEN];
unsigned int dmac_ptr;
unsigned int pwm_irq_sample_cnt;
unsigned int reserved[9];
};
struct Pico32xMem
@ -496,7 +499,10 @@ struct Pico32xMem
unsigned short drcblk_ram[1 << (18 - SH2_DRCBLK_RAM_SHIFT)];
#endif
unsigned short dram[2][0x20000/2]; // AKA fb
unsigned char m68k_rom[0x10000]; // 0x100; using M68K_BANK_SIZE
union {
unsigned char m68k_rom[0x100];
unsigned char m68k_rom_bank[0x10000]; // M68K_BANK_SIZE
};
unsigned char data_array[2][0x1000]; // cache in SH2s (can be used as RAM)
#ifdef DRC_SH2
unsigned short drcblk_da[2][1 << (12 - SH2_DRCBLK_DA_SHIFT)];
@ -510,14 +516,8 @@ struct Pico32xMem
};
// area.c
PICO_INTERNAL void PicoAreaPackCpu(unsigned char *cpu, int is_sub);
PICO_INTERNAL void PicoAreaUnpackCpu(unsigned char *cpu, int is_sub);
extern void (*PicoLoadStateHook)(void);
// cd/area.c
PICO_INTERNAL int PicoCdSaveState(void *file);
PICO_INTERNAL int PicoCdLoadState(void *file);
typedef struct {
int chunk;
int size;
@ -526,19 +526,9 @@ typedef struct {
extern carthw_state_chunk *carthw_chunks;
#define CHUNK_CARTHW 64
// area.c
typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);
typedef size_t (areaeof)(void *file);
typedef int (areaseek)(void *file, long offset, int whence);
typedef int (areaclose)(void *file);
extern arearw *areaRead; // external read and write function pointers for
extern arearw *areaWrite; // gzip save state ability
extern areaeof *areaEof;
extern areaseek *areaSeek;
extern areaclose *areaClose;
// cart.c
void Byteswap(void *dst, const void *src, int len);
extern int PicoCartResize(int newsize);
extern void Byteswap(void *dst, const void *src, int len);
extern void (*PicoCartMemSetup)(void);
extern void (*PicoCartUnloadHook)(void);
@ -612,6 +602,8 @@ PICO_INTERNAL void SekInit(void);
PICO_INTERNAL int SekReset(void);
PICO_INTERNAL void SekState(int *data);
PICO_INTERNAL void SekSetRealTAS(int use_real);
PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub);
PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub);
void SekStepM68k(void);
void SekInitIdleDet(void);
void SekFinishIdleDet(void);
@ -671,8 +663,8 @@ unsigned int EEPROM_read(void);
// z80 functionality wrappers
PICO_INTERNAL void z80_init(void);
PICO_INTERNAL void z80_pack(unsigned char *data);
PICO_INTERNAL void z80_unpack(unsigned char *data);
PICO_INTERNAL void z80_pack(void *data);
PICO_INTERNAL int z80_unpack(const void *data);
PICO_INTERNAL void z80_reset(void);
PICO_INTERNAL void z80_exit(void);
@ -695,6 +687,7 @@ extern int PsndDacLine;
void PicoPowerMS(void);
void PicoResetMS(void);
void PicoMemSetupMS(void);
void PicoStateLoadedMS(void);
void PicoFrameMS(void);
void PicoFrameDrawOnlyMS(void);
@ -717,6 +710,7 @@ void PicoWrite8_32x(unsigned int a, unsigned int d);
void PicoWrite16_32x(unsigned int a, unsigned int d);
void PicoMemSetup32x(void);
void Pico32xSwapDRAM(int b);
void Pico32xStateLoaded(void);
void p32x_poll_event(int cpu_mask, int is_vdp);
// 32x/draw.c

View file

@ -50,12 +50,13 @@ static void SekResetAck(void)
static int SekUnrecognizedOpcode()
{
unsigned int pc, op;
unsigned int pc;
pc = SekPc;
op = PicoCpuCM68k.read16(pc);
elprintf(EL_ANOMALY, "Unrecognized Opcode %04x @ %06x", op, pc);
// see if we are not executing trash
if (pc < 0x200 || (pc > Pico.romsize+4 && (pc&0xe00000)!=0xe00000)) {
elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", pc);
// see if we are still in a mapped region
pc &= 0x00ffffff;
if (map_flag_set(m68k_read16_map[pc >> M68K_MEM_SHIFT])) {
elprintf(EL_STATUS|EL_ANOMALY, "m68k crash @%06x", pc);
PicoCpuCM68k.cycles = 0;
PicoCpuCM68k.state_flags |= 1;
return 1;
@ -184,6 +185,79 @@ PICO_INTERNAL void SekSetRealTAS(int use_real)
#endif
}
// Pack the cpu into a common format:
// XXX: rename
PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
{
unsigned int pc=0;
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
memcpy(cpu,context->d,0x40);
pc=context->pc-context->membase;
*(unsigned int *)(cpu+0x44)=CycloneGetSr(context);
*(unsigned int *)(cpu+0x48)=context->osp;
cpu[0x4c] = context->irq;
cpu[0x4d] = context->state_flags & 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
memcpy(cpu,m68ki_cpu_p->dar,0x40);
pc=m68ki_cpu_p->pc;
*(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
*(unsigned int *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
cpu[0x4c] = CPU_INT_LEVEL>>8;
cpu[0x4d] = CPU_STOPPED;
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(cpu,context->dreg,0x40);
pc=context->pc;
*(unsigned int *)(cpu+0x44)=context->sr;
*(unsigned int *)(cpu+0x48)=context->asp;
cpu[0x4c] = context->interrupts[0];
cpu[0x4d] = (context->execinfo & FM68K_HALTED) ? 1 : 0;
#endif
*(unsigned int *)(cpu+0x40)=pc;
}
PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub)
{
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
CycloneSetSr(context, *(unsigned int *)(cpu+0x44));
context->osp=*(unsigned int *)(cpu+0x48);
memcpy(context->d,cpu,0x40);
context->membase = 0;
context->pc = *(unsigned int *)(cpu+0x40);
CycloneUnpack(context, NULL); // rebase PC
context->irq = cpu[0x4c];
context->state_flags = 0;
if (cpu[0x4d])
context->state_flags |= 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
memcpy(m68ki_cpu_p->dar,cpu,0x40);
m68ki_cpu_p->pc=*(unsigned int *)(cpu+0x40);
m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(unsigned int *)(cpu+0x48);
CPU_INT_LEVEL = cpu[0x4c] << 8;
CPU_STOPPED = cpu[0x4d];
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(context->dreg,cpu,0x40);
context->pc =*(unsigned int *)(cpu+0x40);
context->sr =*(unsigned int *)(cpu+0x44);
context->asp=*(unsigned int *)(cpu+0x48);
context->interrupts[0] = cpu[0x4c];
context->execinfo &= ~FM68K_HALTED;
if (cpu[0x4d]&1) context->execinfo |= FM68K_HALTED;
#endif
}
/* idle loop detection, not to be used in CD mode */
#ifdef EMU_C68K

View file

@ -103,7 +103,7 @@ static unsigned char z80_sms_in(unsigned short a)
break;
case 0xc1: /* I/O port B and miscellaneous */
d = (Pico.sms_io_ctl & 0x80) | ((Pico.sms_io_ctl << 1) & 0x40) | 0x30;
d = (Pico.ms.io_ctl & 0x80) | ((Pico.ms.io_ctl << 1) & 0x40) | 0x30;
d |= ~(PicoPad[1] >> 2) & 0x0f;
break;
}
@ -119,7 +119,7 @@ static void z80_sms_out(unsigned short a, unsigned char d)
switch (a)
{
case 0x01:
Pico.sms_io_ctl = d;
Pico.ms.io_ctl = d;
break;
case 0x40:
@ -167,6 +167,7 @@ static void write_bank(unsigned short a, unsigned char d)
#endif
break;
}
Pico.ms.carthw[a & 0x0f] = d;
}
static void xwrite(unsigned int a, unsigned char d)
@ -174,7 +175,7 @@ static void xwrite(unsigned int a, unsigned char d)
elprintf(EL_IO, "z80 write [%04x] %02x", a, d);
if (a >= 0xc000)
Pico.zram[a & 0x1fff] = d;
if (a >= 0xfff0)
if (a >= 0xfff8)
write_bank(a, d);
}
@ -203,6 +204,9 @@ void PicoPowerMS(void)
tmp = 1 << s;
bank_mask = (tmp - 1) >> 14;
Pico.ms.carthw[0x0e] = 1;
Pico.ms.carthw[0x0f] = 2;
PicoReset();
}
@ -229,6 +233,12 @@ void PicoMemSetupMS(void)
#endif
}
void PicoStateLoadedMS(void)
{
write_bank(0xfffe, Pico.ms.carthw[0x0e]);
write_bank(0xffff, Pico.ms.carthw[0x0f]);
}
void PicoFrameMS(void)
{
struct PicoVideo *pv = &Pico.video;

679
pico/state.c Normal file
View file

@ -0,0 +1,679 @@
// (c) Copyright 2004 Dave, All rights reserved.
// (c) Copyright 2006-2010 notaz, All rights reserved.
// Free for non-commercial use.
// For commercial use, separate licencing terms must be obtained.
#include "pico_int.h"
#include <zlib/zlib.h>
#include "../cpu/sh2/sh2.h"
#include "sound/ym2612.h"
// sn76496
extern int *sn76496_regs;
typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);
typedef size_t (areaeof)(void *file);
typedef int (areaseek)(void *file, long offset, int whence);
typedef int (areaclose)(void *file);
static arearw *areaRead;
static arearw *areaWrite;
static areaeof *areaEof;
static areaseek *areaSeek;
static areaclose *areaClose;
carthw_state_chunk *carthw_chunks;
void (*PicoStateProgressCB)(const char *str);
void (*PicoLoadStateHook)(void);
/* I/O functions */
static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)
{
return gzread(file, p, _size * _n);
}
static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)
{
return gzwrite(file, p, _size * _n);
}
static void set_cbs(int gz)
{
if (gz) {
areaRead = gzRead2;
areaWrite = gzWrite2;
areaEof = (areaeof *) gzeof;
areaSeek = (areaseek *) gzseek;
areaClose = (areaclose *) gzclose;
} else {
areaRead = (arearw *) fread;
areaWrite = (arearw *) fwrite;
areaEof = (areaeof *) feof;
areaSeek = (areaseek *) fseek;
areaClose = (areaclose *) fclose;
}
}
static void *open_save_file(const char *fname, int is_save)
{
int len = strlen(fname);
void *afile = NULL;
if (len > 3 && strcmp(fname + len - 3, ".gz") == 0)
{
if ( (afile = gzopen(fname, is_save ? "wb" : "rb")) ) {
set_cbs(1);
if (is_save)
gzsetparams(afile, 9, Z_DEFAULT_STRATEGY);
}
}
else
{
if ( (afile = fopen(fname, is_save ? "wb" : "rb")) ) {
set_cbs(0);
}
}
return afile;
}
// legacy savestate loading
#define SCANP(f, x) areaRead(&Pico.x, sizeof(Pico.x), 1, f)
static int state_load_legacy(void *file)
{
unsigned char head[32];
unsigned char cpu[0x60];
unsigned char cpu_z80[Z80_STATE_SIZE];
void *ym2612_regs;
int ok;
memset(&cpu,0,sizeof(cpu));
memset(&cpu_z80,0,sizeof(cpu_z80));
memset(head, 0, sizeof(head));
areaRead(head, sizeof(head), 1, file);
if (strcmp((char *)head, "Pico") != 0)
return -1;
elprintf(EL_STATUS, "legacy savestate");
// Scan all the memory areas:
SCANP(file, ram);
SCANP(file, vram);
SCANP(file, zram);
SCANP(file, cram);
SCANP(file, vsram);
// Pack, scan and unpack the cpu data:
areaRead(cpu, sizeof(cpu), 1, file);
SekUnpackCpu(cpu, 0);
SCANP(file, m);
SCANP(file, video);
ok = areaRead(cpu_z80, sizeof(cpu_z80), 1, file) == sizeof(cpu_z80);
// do not unpack if we fail to load z80 state
if (!ok) z80_reset();
else z80_unpack(cpu_z80);
ym2612_regs = YM2612GetRegs();
areaRead(sn76496_regs, 28*4, 1, file);
areaRead(ym2612_regs, 0x200+4, 1, file);
ym2612_unpack_state();
return 0;
}
// ---------------------------------------------------------------------------
typedef enum {
CHUNK_M68K = 1,
CHUNK_RAM,
CHUNK_VRAM,
CHUNK_ZRAM,
CHUNK_CRAM, // 5
CHUNK_VSRAM,
CHUNK_MISC,
CHUNK_VIDEO,
CHUNK_Z80,
CHUNK_PSG, // 10
CHUNK_FM,
// CD stuff
CHUNK_S68K,
CHUNK_PRG_RAM,
CHUNK_WORD_RAM,
CHUNK_PCM_RAM, // 15
CHUNK_BRAM,
CHUNK_GA_REGS,
CHUNK_PCM,
CHUNK_CDC,
CHUNK_CDD, // 20
CHUNK_SCD,
CHUNK_RC,
CHUNK_MISC_CD,
//
CHUNK_IOPORTS, // versions < 1.70 did not save that..
CHUNK_SMS, // 25
// 32x
CHUNK_MSH2,
CHUNK_MSH2_DATA,
CHUNK_MSH2_PERI,
CHUNK_SSH2,
CHUNK_SSH2_DATA, // 30
CHUNK_SSH2_PERI,
CHUNK_32XSYS,
CHUNK_M68K_BIOS,
CHUNK_MSH2_BIOS,
CHUNK_SSH2_BIOS, // 35
CHUNK_SDRAM,
CHUNK_DRAM,
CHUNK_32XPAL,
//
CHUNK_DEFAULT_COUNT,
CHUNK_CARTHW_ = CHUNK_CARTHW, // defined in PicoInt
} chunk_name_e;
static const char * const chunk_names[] = {
"INVALID!",
"M68K state",
"RAM",
"VRAM",
"ZRAM",
"CRAM", // 5
"VSRAM",
"emu state",
"VIDEO",
"Z80 state",
"PSG", // 10
"FM",
// CD stuff
"S68K state",
"PRG_RAM",
"WORD_RAM",
"PCM_RAM", // 15
"BRAM",
"GATE ARRAY regs",
"PCM state",
"CDC",
"CDD", // 20
"SCD",
"GFX chip",
"MCD state",
//
"IO",
"SMS state", // 25
// 32x
"MSH2",
"MSH2 data",
"MSH2 peri",
"SSH2",
"SSH2 data", // 30
"SSH2 peri",
"32X system regs",
"M68K BIOS",
"MSH2 BIOS",
"SSH2 BIOS", // 35
"SDRAM",
"DRAM",
"PAL",
};
static int write_chunk(chunk_name_e name, int len, void *data, void *file)
{
size_t bwritten = 0;
bwritten += areaWrite(&name, 1, 1, file);
bwritten += areaWrite(&len, 1, 4, file);
bwritten += areaWrite(data, 1, len, file);
return (bwritten == len + 4 + 1);
}
#define CHECKED_WRITE(name,len,data) { \
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \
strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \
PicoStateProgressCB(sbuff); \
} \
if (!write_chunk(name, len, data, file)) return 1; \
}
#define CHECKED_WRITE_BUFF(name,buff) { \
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \
strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \
PicoStateProgressCB(sbuff); \
} \
if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \
}
static int state_save(void *file)
{
char sbuff[32] = "Saving.. ";
unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];
void *ym2612_regs = YM2612GetRegs();
int ver = 0x0170; // not really used..
areaWrite("PicoSEXT", 1, 8, file);
areaWrite(&ver, 1, 4, file);
if (!(PicoAHW & PAHW_SMS)) {
memset(buff, 0, sizeof(buff));
SekPackCpu(buff, 0);
CHECKED_WRITE_BUFF(CHUNK_M68K, buff);
CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);
CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);
CHECKED_WRITE_BUFF(CHUNK_IOPORTS, Pico.ioports);
ym2612_pack_state();
CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);
}
else {
CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);
}
CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);
CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);
CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);
CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);
CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);
z80_pack(buff_z80);
CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);
CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);
if (PicoAHW & PAHW_MCD)
{
memset(buff, 0, sizeof(buff));
SekPackCpu(buff, 1);
if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?
wram_1M_to_2M(Pico_mcd->word_ram2M);
Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);
CHECKED_WRITE_BUFF(CHUNK_S68K, buff);
CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);
CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format
CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);
CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);
CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs
CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);
CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);
CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);
CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);
CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);
CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);
if (Pico_mcd->s68k_regs[3] & 4) // convert back
wram_2M_to_1M(Pico_mcd->word_ram2M);
}
if (PicoAHW & PAHW_32X)
{
unsigned char cpubuff[SH2_STATE_SIZE];
memset(cpubuff, 0, sizeof(cpubuff));
sh2_pack(&sh2s[0], cpubuff);
CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);
CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, Pico32xMem->data_array[0]);
CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, Pico32xMem->sh2_peri_regs[0]);
sh2_pack(&sh2s[1], cpubuff);
CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);
CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, Pico32xMem->data_array[1]);
CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, Pico32xMem->sh2_peri_regs[1]);
CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);
CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);
CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);
CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);
CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);
CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);
CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);
}
if (carthw_chunks != NULL)
{
carthw_state_chunk *chwc;
if (PicoStateProgressCB)
PicoStateProgressCB("Saving.. cart hw state");
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)
CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);
}
return 0;
}
static int g_read_offs = 0;
#define R_ERROR_RETURN(error) \
{ \
elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \
return 1; \
}
// when is eof really set?
#define CHECKED_READ(len,data) { \
if (areaRead(data, 1, len, file) != len) { \
if (len == 1 && areaEof(file)) goto readend; \
R_ERROR_RETURN("areaRead: premature EOF\n"); \
return 1; \
} \
g_read_offs += len; \
}
#define CHECKED_READ2(len2,data) { \
if (len2 != len) { \
elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \
if (len > len2) R_ERROR_RETURN("failed."); \
/* else read anyway and hope for the best.. */ \
} \
CHECKED_READ(len, data); \
}
#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);
static int state_load(void *file)
{
unsigned char buff_m68k[0x60], buff_s68k[0x60];
unsigned char buff_z80[Z80_STATE_SIZE];
unsigned char buff_sh2[SH2_STATE_SIZE];
unsigned char chunk;
void *ym2612_regs;
char header[8];
int ver, len;
g_read_offs = 0;
CHECKED_READ(8, header);
if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))
R_ERROR_RETURN("bad header");
CHECKED_READ(4, &ver);
while (!areaEof(file))
{
CHECKED_READ(1, &chunk);
CHECKED_READ(4, &len);
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
R_ERROR_RETURN("cd chunk in non CD state?");
if (CHUNK_MSH2 <= chunk && chunk <= CHUNK_32XPAL && !(PicoAHW & PAHW_32X))
R_ERROR_RETURN("32x chunk in non 32x state?");
switch (chunk)
{
case CHUNK_M68K:
CHECKED_READ_BUFF(buff_m68k);
break;
case CHUNK_Z80:
CHECKED_READ_BUFF(buff_z80);
z80_unpack(buff_z80);
break;
case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;
case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;
case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;
case CHUNK_IOPORTS: CHECKED_READ_BUFF(Pico.ioports); break;
case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;
case CHUNK_FM:
ym2612_regs = YM2612GetRegs();
CHECKED_READ2(0x200+4, ym2612_regs);
ym2612_unpack_state();
break;
case CHUNK_SMS:
CHECKED_READ_BUFF(Pico.ms);
break;
// cd stuff
case CHUNK_S68K:
CHECKED_READ_BUFF(buff_s68k);
break;
case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;
case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;
case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;
case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;
case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;
case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;
case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;
case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;
case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;
case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;
case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;
// 32x stuff
case CHUNK_MSH2:
CHECKED_READ_BUFF(buff_sh2);
sh2_unpack(&sh2s[0], buff_sh2);
break;
case CHUNK_SSH2:
CHECKED_READ_BUFF(buff_sh2);
sh2_unpack(&sh2s[1], buff_sh2);
break;
case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[0]); break;
case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[0]); break;
case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[1]); break;
case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[1]); break;
case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;
case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;
case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;
case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;
case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;
case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;
case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;
default:
if (carthw_chunks != NULL)
{
carthw_state_chunk *chwc;
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {
if (chwc->chunk == chunk) {
CHECKED_READ2(chwc->size, chwc->ptr);
goto breakswitch;
}
}
}
elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);
areaSeek(file, len, SEEK_CUR);
break;
}
breakswitch:;
}
readend:
if (PicoAHW & PAHW_SMS)
PicoStateLoadedMS();
if (PicoAHW & PAHW_MCD)
{
PicoMemStateLoaded();
if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))
cdda_start_play();
// must unpack after mem is set up
SekUnpackCpu(buff_s68k, 1);
}
if (!(PicoAHW & PAHW_SMS))
SekUnpackCpu(buff_m68k, 0);
if (PicoAHW & PAHW_32X)
Pico32xStateLoaded();
return 0;
}
static int state_load_gfx(void *file)
{
int ver, len, found = 0, to_find = 4;
char buff[8];
if (PicoAHW & PAHW_32X)
to_find += 2;
g_read_offs = 0;
CHECKED_READ(8, buff);
if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))
R_ERROR_RETURN("bad header");
CHECKED_READ(4, &ver);
while (!areaEof(file) && found < to_find)
{
CHECKED_READ(1, buff);
CHECKED_READ(4, &len);
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
R_ERROR_RETURN("cd chunk in non CD state?");
switch (buff[0])
{
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;
case CHUNK_DRAM:
if (Pico32xMem != NULL)
CHECKED_READ_BUFF(Pico32xMem->dram);
break;
case CHUNK_32XPAL:
if (Pico32xMem != NULL)
CHECKED_READ_BUFF(Pico32xMem->pal);
Pico32x.dirty_pal = 1;
break;
case CHUNK_32XSYS:
CHECKED_READ_BUFF(Pico32x);
break;
default:
areaSeek(file, len, SEEK_CUR);
break;
}
}
readend:
return 0;
}
int PicoState(const char *fname, int is_save)
{
void *afile = NULL;
int ret;
afile = open_save_file(fname, is_save);
if (afile == NULL)
return -1;
if (is_save)
ret = state_save(afile);
else {
ret = state_load(afile);
if (ret != 0) {
areaSeek(afile, 0, SEEK_SET);
ret = state_load_legacy(afile);
}
if (PicoLoadStateHook != NULL)
PicoLoadStateHook();
Pico.m.dirtyPal = 1;
}
areaClose(afile);
return ret;
}
int PicoStateLoadGfx(const char *fname)
{
void *afile;
int ret;
afile = open_save_file(fname, 0);
if (afile == NULL)
return -1;
ret = state_load_gfx(afile);
if (ret != 0) {
// assume legacy
areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM
areaRead(Pico.vram, 1, sizeof(Pico.vram), afile);
areaSeek(afile, 0x2000, SEEK_CUR);
areaRead(Pico.cram, 1, sizeof(Pico.cram), afile);
areaRead(Pico.vsram, 1, sizeof(Pico.vsram), afile);
areaSeek(afile, 0x221a0, SEEK_SET);
areaRead(&Pico.video, 1, sizeof(Pico.video), afile);
}
areaClose(afile);
return 0;
}
// tmp state
struct PicoTmp
{
unsigned short vram[0x8000];
unsigned short cram[0x40];
unsigned short vsram[0x40];
//struct PicoMisc m;
struct PicoVideo video;
struct {
struct Pico32x p32x;
unsigned short dram[2][0x20000/2];
unsigned short pal[0x100];
} t32x;
};
// returns data ptr to free() or PicoTmpStateRestore()
void *PicoTmpStateSave(void)
{
// gfx only for now
struct PicoTmp *t = malloc(sizeof(*t));
if (t == NULL)
return NULL;
memcpy(t->vram, Pico.vram, sizeof(Pico.vram));
memcpy(t->cram, Pico.cram, sizeof(Pico.cram));
memcpy(t->vsram, Pico.vsram, sizeof(Pico.vsram));
memcpy(&t->video, &Pico.video, sizeof(Pico.video));
if (PicoAHW & PAHW_32X) {
memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));
memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));
memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));
}
return t;
}
void PicoTmpStateRestore(void *data)
{
struct PicoTmp *t = data;
if (t == NULL)
return;
memcpy(Pico.vram, t->vram, sizeof(Pico.vram));
memcpy(Pico.cram, t->cram, sizeof(Pico.cram));
memcpy(Pico.vsram, t->vsram, sizeof(Pico.vsram));
memcpy(&Pico.video, &t->video, sizeof(Pico.video));
Pico.m.dirtyPal = 1;
if (PicoAHW & PAHW_32X) {
memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));
memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));
memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));
Pico32x.dirty_pal = 1;
}
}
// vim:shiftwidth=2:expandtab

View file

@ -5,72 +5,60 @@
uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
#ifdef _USE_MZ80
// memhandlers for mz80 core
unsigned char mz80_read(UINT32 a, struct MemoryReadByte *w) { return z80_read(a); }
void mz80_write(UINT32 a, UINT8 d, struct MemoryWriteByte *w) { z80_write(d, a); }
// structures for mz80 core
static struct MemoryReadByte mz80_mem_read[]=
{
{0x0000,0xffff,mz80_read},
{(UINT32) -1,(UINT32) -1,NULL}
};
static struct MemoryWriteByte mz80_mem_write[]=
{
{0x0000,0xffff,mz80_write},
{(UINT32) -1,(UINT32) -1,NULL}
};
static struct z80PortRead mz80_io_read[] ={
{(UINT16) -1,(UINT16) -1,NULL}
};
static struct z80PortWrite mz80_io_write[]={
{(UINT16) -1,(UINT16) -1,NULL}
};
int mz80_run(int cycles)
{
int ticks_pre = mz80GetElapsedTicks(0);
mz80exec(cycles);
return mz80GetElapsedTicks(0) - ticks_pre;
}
#endif
#ifdef _USE_DRZ80
struct DrZ80 drZ80;
#endif
static u32 drz80_sp_base;
PICO_INTERNAL void z80_init(void)
static void drz80_load_pcsp(u32 pc, u32 sp)
{
#ifdef _USE_MZ80
struct mz80context z80;
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
if (drZ80.Z80PC_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad PC: %04x", pc);
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0];
} else {
drZ80.Z80PC_BASE <<= 1;
drZ80.Z80PC = drZ80.Z80PC_BASE + pc;
}
drZ80.Z80SP_BASE = z80_read_map[sp >> Z80_MEM_SHIFT];
if (drZ80.Z80SP_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad SP: %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[0];
drZ80.Z80SP = drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT);
} else {
drZ80.Z80SP_BASE <<= 1;
drZ80.Z80SP = drZ80.Z80SP_BASE + sp;
}
}
// z80
mz80init();
// Modify the default context
mz80GetContext(&z80);
// called only if internal xmap rebase fails
static unsigned int dz80_rebase_pc(unsigned short pc)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_pc: fail on %04x", pc);
drZ80.Z80PC_BASE = z80_read_map[0] << 1;
return drZ80.Z80PC_BASE;
}
// point mz80 stuff
z80.z80Base=Pico.zram;
z80.z80MemRead=mz80_mem_read;
z80.z80MemWrite=mz80_mem_write;
z80.z80IoRead=mz80_io_read;
z80.z80IoWrite=mz80_io_write;
mz80SetContext(&z80);
static unsigned int dz80_rebase_sp(unsigned short sp)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_sp: fail on %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
return drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT) - 0x100;
}
#endif
void z80_init(void)
{
#ifdef _USE_DRZ80
memset(&drZ80, 0, sizeof(drZ80));
drZ80.z80_rebasePC=NULL; // unused, handled by xmap
drZ80.z80_rebaseSP=NULL;
drZ80.z80_read8 =(void *)z80_read_map;
drZ80.z80_read16 =NULL;
drZ80.z80_write8 =(void *)z80_write_map;
drZ80.z80_write16 =NULL;
drZ80.z80_irq_callback=NULL;
drZ80.z80_rebasePC = dz80_rebase_pc;
drZ80.z80_rebaseSP = dz80_rebase_sp;
drZ80.z80_read8 = (void *)z80_read_map;
drZ80.z80_read16 = NULL;
drZ80.z80_write8 = (void *)z80_write_map;
drZ80.z80_write16 = NULL;
drZ80.z80_irq_callback = NULL;
#endif
#ifdef _USE_CZ80
memset(&CZ80, 0, sizeof(CZ80));
@ -80,113 +68,206 @@ PICO_INTERNAL void z80_init(void)
#endif
}
PICO_INTERNAL void z80_reset(void)
void z80_reset(void)
{
#ifdef _USE_MZ80
mz80reset();
#endif
#ifdef _USE_DRZ80
memset(&drZ80, 0, 0x54);
drZ80.Z80F = (1<<2); // set ZFlag
drZ80.Z80F2 = (1<<2); // set ZFlag
drZ80.Z80IX = 0xFFFF << 16;
drZ80.Z80IY = 0xFFFF << 16;
drZ80.Z80I = 0;
drZ80.Z80IM = 0; // 1?
drZ80.z80irqvector = 0xff0000; // RST 38h
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
// drZ80 is locked in single bank
drZ80.Z80SP_BASE = ((PicoAHW & PAHW_SMS) ?
z80_read_map[0xc000 >> Z80_MEM_SHIFT] : z80_read_map[0]) << 1;
// drZ80.Z80SP = drZ80.z80_rebaseSP(0x2000); // 0xf000 ?
drz80_sp_base = (PicoAHW & PAHW_SMS) ? 0xc000 : 0x0000;
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
if (PicoAHW & PAHW_SMS)
drZ80.Z80SP = drZ80.Z80SP_BASE + 0xdff0; // simulate BIOS
#endif
#ifdef _USE_CZ80
Cz80_Reset(&CZ80);
Cz80_Set_Reg(&CZ80, CZ80_IX, 0xffff);
Cz80_Set_Reg(&CZ80, CZ80_IY, 0xffff);
Cz80_Set_Reg(&CZ80, CZ80_SP, 0x2000);
if (PicoAHW & PAHW_SMS)
Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
#endif
}
// XXX TODO: should better use universal z80 save format
PICO_INTERNAL void z80_pack(unsigned char *data)
/* save state stuff */
static int z80_unpack_legacy(const void *data)
{
#if defined(_USE_MZ80)
struct mz80context mz80;
*(int *)data = 0x00005A6D; // "mZ"
mz80GetContext(&mz80);
memcpy(data+4, &mz80.z80clockticks, sizeof(mz80)-5*4); // don't save base&memhandlers
#elif defined(_USE_DRZ80)
*(int *)data = 0x015A7244; // "DrZ" v1
// drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE);
// drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE);
memcpy(data+4, &drZ80, 0x54);
#elif defined(_USE_CZ80)
*(int *)data = 0x00007a43; // "Cz"
*(int *)(data+4) = Cz80_Get_Reg(&CZ80, CZ80_PC);
memcpy(data+8, &CZ80, offsetof(cz80_struc, BasePC));
#endif
}
PICO_INTERNAL void z80_unpack(unsigned char *data)
{
#if defined(_USE_MZ80)
if (*(int *)data == 0x00005A6D) { // "mZ" save?
struct mz80context mz80;
mz80GetContext(&mz80);
memcpy(&mz80.z80clockticks, data+4, sizeof(mz80)-5*4);
mz80SetContext(&mz80);
} else {
z80_reset();
z80_int();
}
#elif defined(_USE_DRZ80)
#if defined(_USE_DRZ80)
if (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
int pc, sp;
u32 pc, sp;
memcpy(&drZ80, data+4, 0x54);
pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
// update bases
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
if (drZ80.Z80PC & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "bad PC in z80 save: %04x", pc);
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0];
} else {
drZ80.Z80PC_BASE <<= 1;
drZ80.Z80PC = drZ80.Z80PC_BASE + pc;
}
drZ80.Z80SP_BASE = z80_read_map[sp >> Z80_MEM_SHIFT];
if (drZ80.Z80SP & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "bad SP in z80 save: %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[0];
drZ80.Z80SP = drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT);
} else {
drZ80.Z80SP_BASE <<= 1;
drZ80.Z80SP = drZ80.Z80SP_BASE + sp;
}
} else {
z80_reset();
drZ80.Z80IM = 1;
z80_int(); // try to goto int handler, maybe we won't execute trash there?
drz80_load_pcsp(pc, sp);
return 0;
}
#elif defined(_USE_CZ80)
if (*(int *)data == 0x00007a43) { // "Cz" save?
memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
} else {
z80_reset();
z80_int();
return 0;
}
#endif
return -1;
}
struct z80sr_main {
u8 a, f;
u8 b, c;
u8 d, e;
u8 h, l;
};
struct z80_state {
char magic[4];
// regs
struct z80sr_main m; // main regs
struct z80sr_main a; // alt (') regs
u8 i, r;
u16 ix, iy;
u16 sp;
u16 pc;
// other
u8 halted;
u8 iff1, iff2;
u8 im; // irq mode
u8 irq_pending; // irq line level, 1 if active
u8 irq_vector[3]; // up to 3 byte vector for irq mode0 handling
u8 reserved[8];
};
void z80_pack(void *data)
{
struct z80_state *s = data;
memset(data, 0, Z80_STATE_SIZE);
strcpy(s->magic, "Z80");
#if defined(_USE_DRZ80)
#define DRR8(n) (drZ80.Z80##n >> 24)
#define DRR16(n) (drZ80.Z80##n >> 16)
#define DRR16H(n) (drZ80.Z80##n >> 24)
#define DRR16L(n) ((drZ80.Z80##n >> 16) & 0xff)
s->m.a = DRR8(A); s->m.f = DRR8(F);
s->m.b = DRR16H(BC); s->m.c = DRR16L(BC);
s->m.d = DRR16H(DE); s->m.e = DRR16L(DE);
s->m.h = DRR16H(HL); s->m.l = DRR16L(HL);
s->a.a = DRR8(A2); s->a.f = DRR8(F2);
s->a.b = DRR16H(BC2); s->a.c = DRR16L(BC2);
s->a.d = DRR16H(DE2); s->a.e = DRR16L(DE2);
s->a.h = DRR16H(HL2); s->a.l = DRR16L(HL2);
s->i = DRR8(I); s->r = drZ80.spare;
s->ix = DRR16(IX); s->iy = DRR16(IY);
s->sp = drZ80.Z80SP - drZ80.Z80SP_BASE;
s->pc = drZ80.Z80PC - drZ80.Z80PC_BASE;
s->halted = !!(drZ80.Z80IF & 4);
s->iff1 = !!(drZ80.Z80IF & 1);
s->iff2 = !!(drZ80.Z80IF & 2);
s->im = drZ80.Z80IM;
s->irq_pending = !!drZ80.Z80_IRQ;
s->irq_vector[0] = drZ80.z80irqvector >> 16;
s->irq_vector[1] = drZ80.z80irqvector >> 8;
s->irq_vector[2] = drZ80.z80irqvector;
#elif defined(_USE_CZ80)
{
const cz80_struc *CPU = &CZ80;
s->m.a = zA; s->m.f = zF;
s->m.b = zB; s->m.c = zC;
s->m.d = zD; s->m.e = zE;
s->m.h = zH; s->m.l = zL;
s->a.a = zA2; s->a.f = zF2;
s->a.b = CZ80.BC2.B.H; s->a.c = CZ80.BC2.B.L;
s->a.d = CZ80.DE2.B.H; s->a.e = CZ80.DE2.B.L;
s->a.h = CZ80.HL2.B.H; s->a.l = CZ80.HL2.B.L;
s->i = zI; s->r = zR;
s->ix = zIX; s->iy = zIY;
s->sp = Cz80_Get_Reg(&CZ80, CZ80_SP);
s->pc = Cz80_Get_Reg(&CZ80, CZ80_PC);
s->halted = !!Cz80_Get_Reg(&CZ80, CZ80_HALT);
s->iff1 = !!zIFF1;
s->iff2 = !!zIFF2;
s->im = zIM;
s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) == HOLD_LINE);
s->irq_vector[0] = 0xff;
}
#endif
}
PICO_INTERNAL void z80_exit(void)
int z80_unpack(const void *data)
{
#if defined(_USE_MZ80)
mz80shutdown();
const struct z80_state *s = data;
if (strcmp(s->magic, "Z80") != 0) {
if (z80_unpack_legacy(data) != 0)
goto fail;
elprintf(EL_STATUS, "legacy z80 state");
return 0;
}
#if defined(_USE_DRZ80)
#define DRW8(n, v) drZ80.Z80##n = (u32)(v) << 24
#define DRW16(n, v) drZ80.Z80##n = (u32)(v) << 16
#define DRW16HL(n, h, l) drZ80.Z80##n = ((u32)(h) << 24) | ((u32)(l) << 16)
DRW8(A, s->m.a); DRW8(F, s->m.f);
DRW16HL(BC, s->m.b, s->m.c);
DRW16HL(DE, s->m.d, s->m.e);
DRW16HL(HL, s->m.h, s->m.l);
DRW8(A2, s->a.a); DRW8(F2, s->a.f);
DRW16HL(BC2, s->a.b, s->a.c);
DRW16HL(DE2, s->a.d, s->a.e);
DRW16HL(HL2, s->a.h, s->a.l);
DRW8(I, s->i); drZ80.spare = s->r;
DRW16(IX, s->ix); DRW16(IY, s->iy);
drz80_load_pcsp(s->pc, s->sp);
drZ80.Z80IF = 0;
if (s->halted) drZ80.Z80IF |= 4;
if (s->iff1) drZ80.Z80IF |= 1;
if (s->iff2) drZ80.Z80IF |= 2;
drZ80.Z80IM = s->im;
drZ80.Z80_IRQ = s->irq_pending;
drZ80.z80irqvector = ((u32)s->irq_vector[0] << 16) |
((u32)s->irq_vector[1] << 8) | s->irq_vector[2];
return 0;
#elif defined(_USE_CZ80)
{
cz80_struc *CPU = &CZ80;
zA = s->m.a; zF = s->m.f;
zB = s->m.b; zC = s->m.c;
zD = s->m.d; zE = s->m.e;
zH = s->m.h; zL = s->m.l;
zA2 = s->a.a; zF2 = s->a.f;
CZ80.BC2.B.H = s->a.b; CZ80.BC2.B.L = s->a.c;
CZ80.DE2.B.H = s->a.d; CZ80.DE2.B.L = s->a.e;
CZ80.HL2.B.H = s->a.h; CZ80.HL2.B.L = s->a.l;
zI = s->i; zR = s->r;
zIX = s->ix; zIY = s->iy;
Cz80_Set_Reg(&CZ80, CZ80_SP, s->sp);
Cz80_Set_Reg(&CZ80, CZ80_PC, s->pc);
Cz80_Set_Reg(&CZ80, CZ80_HALT, s->halted);
Cz80_Set_Reg(&CZ80, CZ80_IFF1, s->iff1);
Cz80_Set_Reg(&CZ80, CZ80_IFF2, s->iff2);
zIM = s->im;
Cz80_Set_Reg(&CZ80, CZ80_IRQ, s->irq_pending ? HOLD_LINE : CLEAR_LINE);
return 0;
}
#endif
fail:
elprintf(EL_STATUS|EL_ANOMALY, "z80_unpack failed");
z80_reset();
z80_int();
return -1;
}
PICO_INTERNAL void z80_debug(char *dstr)
void z80_exit(void)
{
}
void z80_debug(char *dstr)
{
#if defined(_USE_DRZ80)
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);