mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
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:
parent
a736af3ecf
commit
b4db550e41
19 changed files with 1116 additions and 848 deletions
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
.if DRZ80_XMAP
|
.if DRZ80_XMAP
|
||||||
.equ Z80_MEM_SHIFT, 13
|
.equ Z80_MEM_SHIFT, 13
|
||||||
;@ note: stack is locked in single bank that z80sp_base points to
|
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if INTERRUPT_MODE
|
.if INTERRUPT_MODE
|
||||||
|
@ -206,12 +205,30 @@ z80_xmap_rebase_pc:
|
||||||
bxcc lr
|
bxcc lr
|
||||||
|
|
||||||
z80_bad_jump:
|
z80_bad_jump:
|
||||||
ldr r0,[cpucontext,#z80_read8]
|
stmfd sp!,{r3,r12,lr}
|
||||||
ldr r0,[r0]
|
mov lr,pc
|
||||||
str r0,[cpucontext,#z80pc_base]
|
ldr pc,[cpucontext,#z80_rebasePC]
|
||||||
mov z80pc,r0
|
mov z80pc,r0
|
||||||
bx lr
|
ldmfd sp!,{r3,r12,pc}
|
||||||
.endif
|
|
||||||
|
z80_xmap_rebase_sp:
|
||||||
|
ldr r1,[cpucontext,#z80_read8]
|
||||||
|
sub r2,r0,#1
|
||||||
|
mov r2,r2,lsl #16
|
||||||
|
mov r2,r2,lsr #(Z80_MEM_SHIFT+16)
|
||||||
|
ldr r1,[r1,r2,lsl #2]
|
||||||
|
movs r1,r1,lsl #1
|
||||||
|
strcc r1,[cpucontext,#z80sp_base]
|
||||||
|
addcc z80sp,r1,r0
|
||||||
|
bxcc lr
|
||||||
|
|
||||||
|
stmfd sp!,{r3,r12,lr}
|
||||||
|
mov lr,pc
|
||||||
|
ldr pc,[cpucontext,#z80_rebaseSP]
|
||||||
|
mov z80sp,r0
|
||||||
|
ldmfd sp!,{r3,r12,pc}
|
||||||
|
|
||||||
|
.endif @ DRZ80_XMAP
|
||||||
|
|
||||||
|
|
||||||
.macro fetch cycs
|
.macro fetch cycs
|
||||||
|
@ -367,15 +384,13 @@ z80_bad_jump:
|
||||||
str z80pc,[cpucontext,#z80pc_pointer]
|
str z80pc,[cpucontext,#z80pc_pointer]
|
||||||
.endif
|
.endif
|
||||||
.if DRZ80_XMAP
|
.if DRZ80_XMAP
|
||||||
;@ XXX: SP is locked to single back z80sp_base points to.
|
bl z80_xmap_rebase_sp
|
||||||
ldr r1,[cpucontext,#z80sp_base]
|
|
||||||
bic r0,r0,#0x7f<<Z80_MEM_SHIFT
|
|
||||||
add r0,r1,r0
|
|
||||||
.else
|
.else
|
||||||
stmfd sp!,{r3,r12}
|
stmfd sp!,{r3,r12}
|
||||||
mov lr,pc
|
mov lr,pc
|
||||||
ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp
|
ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp
|
||||||
ldmfd sp!,{r3,r12}
|
ldmfd sp!,{r3,r12}
|
||||||
|
mov z80sp,r0
|
||||||
.endif
|
.endif
|
||||||
.endm
|
.endm
|
||||||
;@----------------------------------------------------------------------------
|
;@----------------------------------------------------------------------------
|
||||||
|
@ -4492,7 +4507,6 @@ opcode_3_1:
|
||||||
.if FAST_Z80SP
|
.if FAST_Z80SP
|
||||||
orr r0,r0,r1, lsl #8
|
orr r0,r0,r1, lsl #8
|
||||||
rebasesp
|
rebasesp
|
||||||
mov z80sp,r0
|
|
||||||
.else
|
.else
|
||||||
orr z80sp,r0,r1, lsl #8
|
orr z80sp,r0,r1, lsl #8
|
||||||
.endif
|
.endif
|
||||||
|
@ -5567,7 +5581,6 @@ opcode_F_9:
|
||||||
.if FAST_Z80SP
|
.if FAST_Z80SP
|
||||||
mov r0,z80hl, lsr #16
|
mov r0,z80hl, lsr #16
|
||||||
rebasesp
|
rebasesp
|
||||||
mov z80sp,r0
|
|
||||||
.else
|
.else
|
||||||
mov z80sp,z80hl, lsr #16
|
mov z80sp,z80hl, lsr #16
|
||||||
.endif
|
.endif
|
||||||
|
@ -7433,7 +7446,6 @@ opcode_DD_F9:
|
||||||
.if FAST_Z80SP
|
.if FAST_Z80SP
|
||||||
ldrh r0,[z80xx,#2]
|
ldrh r0,[z80xx,#2]
|
||||||
rebasesp
|
rebasesp
|
||||||
mov z80sp,r0
|
|
||||||
.else
|
.else
|
||||||
ldrh z80sp,[z80xx,#2]
|
ldrh z80sp,[z80xx,#2]
|
||||||
.endif
|
.endif
|
||||||
|
@ -7771,8 +7783,9 @@ opcode_ED_7B:
|
||||||
readmem16
|
readmem16
|
||||||
.if FAST_Z80SP
|
.if FAST_Z80SP
|
||||||
rebasesp
|
rebasesp
|
||||||
.endif
|
.else
|
||||||
mov z80sp,r0
|
mov z80sp,r0
|
||||||
|
.endif
|
||||||
fetch 20
|
fetch 20
|
||||||
;@LDI
|
;@LDI
|
||||||
opcode_ED_A0:
|
opcode_ED_A0:
|
||||||
|
|
|
@ -394,8 +394,8 @@ void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)
|
||||||
case CZ80_R: zR = val; break;
|
case CZ80_R: zR = val; break;
|
||||||
case CZ80_I: zI = val; break;
|
case CZ80_I: zI = val; break;
|
||||||
case CZ80_IM: zIM = val; break;
|
case CZ80_IM: zIM = val; break;
|
||||||
case CZ80_IFF1: zIFF1 = val; break;
|
case CZ80_IFF1: zIFF1 = val ? (1 << 2) : 0; break;
|
||||||
case CZ80_IFF2: zIFF2 = val; break;
|
case CZ80_IFF2: zIFF2 = val ? (1 << 2) : 0; break;
|
||||||
case CZ80_HALT: CPU->HaltState = val; break;
|
case CZ80_HALT: CPU->HaltState = val; break;
|
||||||
case CZ80_IRQ: CPU->IRQState = val; break;
|
case CZ80_IRQ: CPU->IRQState = val; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "sh2.h"
|
#include "sh2.h"
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
@ -85,3 +87,31 @@ void sh2_internal_irq(SH2 *sh2, int level, int vector)
|
||||||
sh2->test_irq = 1;
|
sh2->test_irq = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SH2_REG_SIZE (offsetof(SH2, macl) + sizeof(sh2->macl))
|
||||||
|
|
||||||
|
void sh2_pack(const SH2 *sh2, unsigned char *buff)
|
||||||
|
{
|
||||||
|
unsigned int *p;
|
||||||
|
|
||||||
|
memcpy(buff, sh2, SH2_REG_SIZE);
|
||||||
|
p = (void *)(buff + SH2_REG_SIZE);
|
||||||
|
|
||||||
|
p[0] = sh2->pending_int_irq;
|
||||||
|
p[1] = sh2->pending_int_vector;
|
||||||
|
p[2] = sh2->cycles_aim;
|
||||||
|
p[3] = sh2->cycles_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sh2_unpack(SH2 *sh2, const unsigned char *buff)
|
||||||
|
{
|
||||||
|
unsigned int *p;
|
||||||
|
|
||||||
|
memcpy(sh2, buff, SH2_REG_SIZE);
|
||||||
|
p = (void *)(buff + SH2_REG_SIZE);
|
||||||
|
|
||||||
|
sh2->pending_int_irq = p[0];
|
||||||
|
sh2->pending_int_vector = p[1];
|
||||||
|
sh2->cycles_aim = p[2];
|
||||||
|
sh2->cycles_done = p[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,9 +64,14 @@ void sh2_reset(SH2 *sh2);
|
||||||
void sh2_irl_irq(SH2 *sh2, int level, int nested_call);
|
void sh2_irl_irq(SH2 *sh2, int level, int nested_call);
|
||||||
void sh2_internal_irq(SH2 *sh2, int level, int vector);
|
void sh2_internal_irq(SH2 *sh2, int level, int vector);
|
||||||
void sh2_do_irq(SH2 *sh2, int level, int vector);
|
void sh2_do_irq(SH2 *sh2, int level, int vector);
|
||||||
|
void sh2_pack(const SH2 *sh2, unsigned char *buff);
|
||||||
|
void sh2_unpack(SH2 *sh2, const unsigned char *buff);
|
||||||
|
|
||||||
void sh2_execute(SH2 *sh2, int cycles);
|
void sh2_execute(SH2 *sh2, int cycles);
|
||||||
|
|
||||||
|
// regs, pending_int*, cycles, reserved
|
||||||
|
#define SH2_STATE_SIZE ((24 + 2 + 2 + 12) * 4)
|
||||||
|
|
||||||
// pico memhandlers
|
// pico memhandlers
|
||||||
// XXX: move somewhere else
|
// XXX: move somewhere else
|
||||||
unsigned int REGPARM(2) p32x_sh2_read8(unsigned int a, SH2 *sh2);
|
unsigned int REGPARM(2) p32x_sh2_read8(unsigned int a, SH2 *sh2);
|
||||||
|
|
|
@ -352,7 +352,7 @@ static void p32x_vdp_write8(u32 a, u32 d)
|
||||||
Pico32x.pending_fb = d;
|
Pico32x.pending_fb = d;
|
||||||
// if we are blanking and FS bit is changing
|
// 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)) {
|
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);
|
Pico32xSwapDRAM(d ^ 1);
|
||||||
elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
|
elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
|
||||||
}
|
}
|
||||||
|
@ -1329,7 +1329,7 @@ static void get_bios(void)
|
||||||
// M68K ROM
|
// M68K ROM
|
||||||
if (p32x_bios_g != NULL) {
|
if (p32x_bios_g != NULL) {
|
||||||
elprintf(EL_STATUS|EL_32X, "32x: using supplied 68k BIOS");
|
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 {
|
else {
|
||||||
// generate 68k ROM
|
// generate 68k ROM
|
||||||
|
@ -1351,7 +1351,9 @@ static void get_bios(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// fill remaining m68k_rom page with game ROM
|
// 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
|
// MSH2
|
||||||
if (p32x_bios_m != NULL) {
|
if (p32x_bios_m != NULL) {
|
||||||
|
@ -1439,9 +1441,9 @@ void PicoMemSetup32x(void)
|
||||||
// m68k_map_unmap(0x000000, 0x3fffff);
|
// m68k_map_unmap(0x000000, 0x3fffff);
|
||||||
|
|
||||||
// MD ROM area
|
// MD ROM area
|
||||||
rs = sizeof(Pico32xMem->m68k_rom);
|
rs = sizeof(Pico32xMem->m68k_rom_bank);
|
||||||
cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
|
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, 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_write8_map, 0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
|
||||||
cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
|
cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
|
||||||
|
|
||||||
|
@ -1538,4 +1540,16 @@ void PicoMemSetup32x(void)
|
||||||
#endif
|
#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
|
// vim:shiftwidth=2:expandtab
|
||||||
|
|
|
@ -145,7 +145,6 @@ void p32x_pwm_write16(unsigned int a, unsigned int d)
|
||||||
|
|
||||||
void p32x_pwm_update(int *buf32, int length, int stereo)
|
void p32x_pwm_update(int *buf32, int length, int stereo)
|
||||||
{
|
{
|
||||||
extern int pwm_ptr;
|
|
||||||
short *pwmb;
|
short *pwmb;
|
||||||
int step;
|
int step;
|
||||||
int p = 0;
|
int p = 0;
|
||||||
|
|
300
pico/area.c
300
pico/area.c
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -439,6 +439,9 @@ static unsigned char *PicoCartAlloc(int filesize, int is_sms)
|
||||||
if (filesize > (1 << s))
|
if (filesize > (1 << s))
|
||||||
s++;
|
s++;
|
||||||
rom_alloc_size = 1 << s;
|
rom_alloc_size = 1 << s;
|
||||||
|
// be sure we can cover all address space
|
||||||
|
if (rom_alloc_size < 0x10000)
|
||||||
|
rom_alloc_size = 0x10000;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// make alloc size at least sizeof(mcd_state),
|
// make alloc size at least sizeof(mcd_state),
|
||||||
|
|
321
pico/cd/area.c
321
pico/cd/area.c
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,7 @@ static u32 PicoRead8_sram(u32 a)
|
||||||
static u32 PicoRead16_sram(u32 a)
|
static u32 PicoRead16_sram(u32 a)
|
||||||
{
|
{
|
||||||
u32 d;
|
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)
|
if (SRam.flags & SRF_EEPROM)
|
||||||
d = EEPROM_read();
|
d = EEPROM_read();
|
||||||
|
|
|
@ -27,7 +27,7 @@ PicoRead8_sram: @ u32 a, u32 d
|
||||||
ldr r3, =(Pico+0x22200)
|
ldr r3, =(Pico+0x22200)
|
||||||
ldr r1, [r2, #8] @ SRam.end
|
ldr r1, [r2, #8] @ SRam.end
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
bge m_read8_nosram
|
bgt m_read8_nosram
|
||||||
ldr r1, [r2, #4] @ SRam.start
|
ldr r1, [r2, #4] @ SRam.start
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
blt m_read8_nosram
|
blt m_read8_nosram
|
||||||
|
@ -58,8 +58,8 @@ m_read8_nosram:
|
||||||
m_read8_eeprom:
|
m_read8_eeprom:
|
||||||
stmfd sp!,{r0,lr}
|
stmfd sp!,{r0,lr}
|
||||||
bl EEPROM_read
|
bl EEPROM_read
|
||||||
ldmfd sp!,{r0,lr}
|
ldmfd sp!,{r1,lr}
|
||||||
tst r0, #1
|
tst r1, #1
|
||||||
moveq r0, r0, lsr #8
|
moveq r0, r0, lsr #8
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ PicoRead16_sram: @ u32 a, u32 d
|
||||||
ldr r3, =(Pico+0x22200)
|
ldr r3, =(Pico+0x22200)
|
||||||
ldr r1, [r2, #8] @ SRam.end
|
ldr r1, [r2, #8] @ SRam.end
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
bge m_read16_nosram
|
bgt m_read16_nosram
|
||||||
ldr r1, [r2, #4] @ SRam.start
|
ldr r1, [r2, #4] @ SRam.start
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
blt m_read16_nosram
|
blt m_read16_nosram
|
||||||
|
|
|
@ -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.
|
// attempt to alloc mem at specified address.
|
||||||
// alloc anywhere else if that fails (callers should handle that)
|
// alloc anywhere else if that fails (callers should handle that)
|
||||||
extern void *plat_mmap(unsigned long addr, size_t size);
|
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);
|
extern void plat_munmap(void *ptr, size_t size);
|
||||||
|
|
||||||
// this one should handle display mode changes
|
// this one should handle display mode changes
|
||||||
|
@ -119,12 +120,11 @@ extern picohw_state PicoPicohw;
|
||||||
|
|
||||||
// area.c
|
// area.c
|
||||||
int PicoState(const char *fname, int is_save);
|
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);
|
extern void (*PicoStateProgressCB)(const char *str);
|
||||||
|
|
||||||
// cd/area.c
|
|
||||||
int PicoCdLoadStateGfx(void *file);
|
|
||||||
|
|
||||||
// cd/buffering.c
|
// cd/buffering.c
|
||||||
void PicoCDBufferInit(void);
|
void PicoCDBufferInit(void);
|
||||||
void PicoCDBufferFree(void);
|
void PicoCDBufferFree(void);
|
||||||
|
|
|
@ -178,14 +178,7 @@ extern int dbg_irq_level;
|
||||||
|
|
||||||
// ----------------------- Z80 CPU -----------------------
|
// ----------------------- Z80 CPU -----------------------
|
||||||
|
|
||||||
#if defined(_USE_MZ80)
|
#if defined(_USE_DRZ80)
|
||||||
#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)
|
|
||||||
#include "../cpu/DrZ80/drz80.h"
|
#include "../cpu/DrZ80/drz80.h"
|
||||||
|
|
||||||
extern struct DrZ80 drZ80;
|
extern struct DrZ80 drZ80;
|
||||||
|
@ -215,6 +208,8 @@ extern struct DrZ80 drZ80;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define Z80_STATE_SIZE 0x60
|
||||||
|
|
||||||
extern int z80stopCycle; /* in 68k cycles */
|
extern int z80stopCycle; /* in 68k cycles */
|
||||||
extern int z80_cycle_cnt; /* 'done' z80 cycles before z80_run() */
|
extern int z80_cycle_cnt; /* 'done' z80 cycles before z80_run() */
|
||||||
extern int z80_cycle_aim;
|
extern int z80_cycle_aim;
|
||||||
|
@ -305,6 +300,13 @@ struct PicoMisc
|
||||||
unsigned int frame_count; // 1c for movies and idle det
|
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!
|
// some assembly stuff depend on these, do not touch!
|
||||||
struct Pico
|
struct Pico
|
||||||
{
|
{
|
||||||
|
@ -314,9 +316,8 @@ struct Pico
|
||||||
unsigned char vramb[0x4000]; // VRAM in SMS mode
|
unsigned char vramb[0x4000]; // VRAM in SMS mode
|
||||||
};
|
};
|
||||||
unsigned char zram[0x2000]; // 0x20000 Z80 ram
|
unsigned char zram[0x2000]; // 0x20000 Z80 ram
|
||||||
unsigned char ioports[0x10];
|
unsigned char ioports[0x10]; // XXX: fix asm and mv
|
||||||
unsigned char sms_io_ctl;
|
unsigned char pad[0xf0]; // unused
|
||||||
unsigned char pad[0xef]; // unused
|
|
||||||
unsigned short cram[0x40]; // 0x22100
|
unsigned short cram[0x40]; // 0x22100
|
||||||
unsigned short vsram[0x40]; // 0x22180
|
unsigned short vsram[0x40]; // 0x22180
|
||||||
|
|
||||||
|
@ -325,6 +326,7 @@ struct Pico
|
||||||
|
|
||||||
struct PicoMisc m;
|
struct PicoMisc m;
|
||||||
struct PicoVideo video;
|
struct PicoVideo video;
|
||||||
|
struct PicoMS ms;
|
||||||
};
|
};
|
||||||
|
|
||||||
// sram
|
// sram
|
||||||
|
@ -487,6 +489,7 @@ struct Pico32x
|
||||||
unsigned short dmac_fifo[DMAC_FIFO_LEN];
|
unsigned short dmac_fifo[DMAC_FIFO_LEN];
|
||||||
unsigned int dmac_ptr;
|
unsigned int dmac_ptr;
|
||||||
unsigned int pwm_irq_sample_cnt;
|
unsigned int pwm_irq_sample_cnt;
|
||||||
|
unsigned int reserved[9];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Pico32xMem
|
struct Pico32xMem
|
||||||
|
@ -496,7 +499,10 @@ struct Pico32xMem
|
||||||
unsigned short drcblk_ram[1 << (18 - SH2_DRCBLK_RAM_SHIFT)];
|
unsigned short drcblk_ram[1 << (18 - SH2_DRCBLK_RAM_SHIFT)];
|
||||||
#endif
|
#endif
|
||||||
unsigned short dram[2][0x20000/2]; // AKA fb
|
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)
|
unsigned char data_array[2][0x1000]; // cache in SH2s (can be used as RAM)
|
||||||
#ifdef DRC_SH2
|
#ifdef DRC_SH2
|
||||||
unsigned short drcblk_da[2][1 << (12 - SH2_DRCBLK_DA_SHIFT)];
|
unsigned short drcblk_da[2][1 << (12 - SH2_DRCBLK_DA_SHIFT)];
|
||||||
|
@ -510,14 +516,8 @@ struct Pico32xMem
|
||||||
};
|
};
|
||||||
|
|
||||||
// area.c
|
// 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);
|
extern void (*PicoLoadStateHook)(void);
|
||||||
|
|
||||||
// cd/area.c
|
|
||||||
PICO_INTERNAL int PicoCdSaveState(void *file);
|
|
||||||
PICO_INTERNAL int PicoCdLoadState(void *file);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int chunk;
|
int chunk;
|
||||||
int size;
|
int size;
|
||||||
|
@ -526,19 +526,9 @@ typedef struct {
|
||||||
extern carthw_state_chunk *carthw_chunks;
|
extern carthw_state_chunk *carthw_chunks;
|
||||||
#define CHUNK_CARTHW 64
|
#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
|
// 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 (*PicoCartMemSetup)(void);
|
||||||
extern void (*PicoCartUnloadHook)(void);
|
extern void (*PicoCartUnloadHook)(void);
|
||||||
|
|
||||||
|
@ -612,6 +602,8 @@ PICO_INTERNAL void SekInit(void);
|
||||||
PICO_INTERNAL int SekReset(void);
|
PICO_INTERNAL int SekReset(void);
|
||||||
PICO_INTERNAL void SekState(int *data);
|
PICO_INTERNAL void SekState(int *data);
|
||||||
PICO_INTERNAL void SekSetRealTAS(int use_real);
|
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 SekStepM68k(void);
|
||||||
void SekInitIdleDet(void);
|
void SekInitIdleDet(void);
|
||||||
void SekFinishIdleDet(void);
|
void SekFinishIdleDet(void);
|
||||||
|
@ -671,8 +663,8 @@ unsigned int EEPROM_read(void);
|
||||||
|
|
||||||
// z80 functionality wrappers
|
// z80 functionality wrappers
|
||||||
PICO_INTERNAL void z80_init(void);
|
PICO_INTERNAL void z80_init(void);
|
||||||
PICO_INTERNAL void z80_pack(unsigned char *data);
|
PICO_INTERNAL void z80_pack(void *data);
|
||||||
PICO_INTERNAL void z80_unpack(unsigned char *data);
|
PICO_INTERNAL int z80_unpack(const void *data);
|
||||||
PICO_INTERNAL void z80_reset(void);
|
PICO_INTERNAL void z80_reset(void);
|
||||||
PICO_INTERNAL void z80_exit(void);
|
PICO_INTERNAL void z80_exit(void);
|
||||||
|
|
||||||
|
@ -695,6 +687,7 @@ extern int PsndDacLine;
|
||||||
void PicoPowerMS(void);
|
void PicoPowerMS(void);
|
||||||
void PicoResetMS(void);
|
void PicoResetMS(void);
|
||||||
void PicoMemSetupMS(void);
|
void PicoMemSetupMS(void);
|
||||||
|
void PicoStateLoadedMS(void);
|
||||||
void PicoFrameMS(void);
|
void PicoFrameMS(void);
|
||||||
void PicoFrameDrawOnlyMS(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 PicoWrite16_32x(unsigned int a, unsigned int d);
|
||||||
void PicoMemSetup32x(void);
|
void PicoMemSetup32x(void);
|
||||||
void Pico32xSwapDRAM(int b);
|
void Pico32xSwapDRAM(int b);
|
||||||
|
void Pico32xStateLoaded(void);
|
||||||
void p32x_poll_event(int cpu_mask, int is_vdp);
|
void p32x_poll_event(int cpu_mask, int is_vdp);
|
||||||
|
|
||||||
// 32x/draw.c
|
// 32x/draw.c
|
||||||
|
|
84
pico/sek.c
84
pico/sek.c
|
@ -50,12 +50,13 @@ static void SekResetAck(void)
|
||||||
|
|
||||||
static int SekUnrecognizedOpcode()
|
static int SekUnrecognizedOpcode()
|
||||||
{
|
{
|
||||||
unsigned int pc, op;
|
unsigned int pc;
|
||||||
pc = SekPc;
|
pc = SekPc;
|
||||||
op = PicoCpuCM68k.read16(pc);
|
elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", pc);
|
||||||
elprintf(EL_ANOMALY, "Unrecognized Opcode %04x @ %06x", op, pc);
|
// see if we are still in a mapped region
|
||||||
// see if we are not executing trash
|
pc &= 0x00ffffff;
|
||||||
if (pc < 0x200 || (pc > Pico.romsize+4 && (pc&0xe00000)!=0xe00000)) {
|
if (map_flag_set(m68k_read16_map[pc >> M68K_MEM_SHIFT])) {
|
||||||
|
elprintf(EL_STATUS|EL_ANOMALY, "m68k crash @%06x", pc);
|
||||||
PicoCpuCM68k.cycles = 0;
|
PicoCpuCM68k.cycles = 0;
|
||||||
PicoCpuCM68k.state_flags |= 1;
|
PicoCpuCM68k.state_flags |= 1;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -184,6 +185,79 @@ PICO_INTERNAL void SekSetRealTAS(int use_real)
|
||||||
#endif
|
#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 */
|
/* idle loop detection, not to be used in CD mode */
|
||||||
#ifdef EMU_C68K
|
#ifdef EMU_C68K
|
||||||
|
|
16
pico/sms.c
16
pico/sms.c
|
@ -103,7 +103,7 @@ static unsigned char z80_sms_in(unsigned short a)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc1: /* I/O port B and miscellaneous */
|
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;
|
d |= ~(PicoPad[1] >> 2) & 0x0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ static void z80_sms_out(unsigned short a, unsigned char d)
|
||||||
switch (a)
|
switch (a)
|
||||||
{
|
{
|
||||||
case 0x01:
|
case 0x01:
|
||||||
Pico.sms_io_ctl = d;
|
Pico.ms.io_ctl = d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x40:
|
case 0x40:
|
||||||
|
@ -167,6 +167,7 @@ static void write_bank(unsigned short a, unsigned char d)
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Pico.ms.carthw[a & 0x0f] = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xwrite(unsigned int a, unsigned char 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);
|
elprintf(EL_IO, "z80 write [%04x] %02x", a, d);
|
||||||
if (a >= 0xc000)
|
if (a >= 0xc000)
|
||||||
Pico.zram[a & 0x1fff] = d;
|
Pico.zram[a & 0x1fff] = d;
|
||||||
if (a >= 0xfff0)
|
if (a >= 0xfff8)
|
||||||
write_bank(a, d);
|
write_bank(a, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +204,9 @@ void PicoPowerMS(void)
|
||||||
tmp = 1 << s;
|
tmp = 1 << s;
|
||||||
bank_mask = (tmp - 1) >> 14;
|
bank_mask = (tmp - 1) >> 14;
|
||||||
|
|
||||||
|
Pico.ms.carthw[0x0e] = 1;
|
||||||
|
Pico.ms.carthw[0x0f] = 2;
|
||||||
|
|
||||||
PicoReset();
|
PicoReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,6 +233,12 @@ void PicoMemSetupMS(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PicoStateLoadedMS(void)
|
||||||
|
{
|
||||||
|
write_bank(0xfffe, Pico.ms.carthw[0x0e]);
|
||||||
|
write_bank(0xffff, Pico.ms.carthw[0x0f]);
|
||||||
|
}
|
||||||
|
|
||||||
void PicoFrameMS(void)
|
void PicoFrameMS(void)
|
||||||
{
|
{
|
||||||
struct PicoVideo *pv = &Pico.video;
|
struct PicoVideo *pv = &Pico.video;
|
||||||
|
|
679
pico/state.c
Normal file
679
pico/state.c
Normal 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
|
323
pico/z80if.c
323
pico/z80if.c
|
@ -5,67 +5,55 @@
|
||||||
uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
|
uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
|
||||||
uptr z80_write_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
|
#ifdef _USE_DRZ80
|
||||||
struct DrZ80 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
|
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
|
||||||
struct mz80context z80;
|
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
|
// called only if internal xmap rebase fails
|
||||||
mz80init();
|
static unsigned int dz80_rebase_pc(unsigned short pc)
|
||||||
// Modify the default context
|
{
|
||||||
mz80GetContext(&z80);
|
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
|
static unsigned int dz80_rebase_sp(unsigned short sp)
|
||||||
z80.z80Base=Pico.zram;
|
{
|
||||||
z80.z80MemRead=mz80_mem_read;
|
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_sp: fail on %04x", sp);
|
||||||
z80.z80MemWrite=mz80_mem_write;
|
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
|
||||||
z80.z80IoRead=mz80_io_read;
|
return drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT) - 0x100;
|
||||||
z80.z80IoWrite=mz80_io_write;
|
}
|
||||||
|
|
||||||
mz80SetContext(&z80);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void z80_init(void)
|
||||||
|
{
|
||||||
#ifdef _USE_DRZ80
|
#ifdef _USE_DRZ80
|
||||||
memset(&drZ80, 0, sizeof(drZ80));
|
memset(&drZ80, 0, sizeof(drZ80));
|
||||||
drZ80.z80_rebasePC=NULL; // unused, handled by xmap
|
drZ80.z80_rebasePC = dz80_rebase_pc;
|
||||||
drZ80.z80_rebaseSP=NULL;
|
drZ80.z80_rebaseSP = dz80_rebase_sp;
|
||||||
drZ80.z80_read8 = (void *)z80_read_map;
|
drZ80.z80_read8 = (void *)z80_read_map;
|
||||||
drZ80.z80_read16 = NULL;
|
drZ80.z80_read16 = NULL;
|
||||||
drZ80.z80_write8 = (void *)z80_write_map;
|
drZ80.z80_write8 = (void *)z80_write_map;
|
||||||
|
@ -80,113 +68,206 @@ PICO_INTERNAL void z80_init(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void z80_reset(void)
|
void z80_reset(void)
|
||||||
{
|
{
|
||||||
#ifdef _USE_MZ80
|
|
||||||
mz80reset();
|
|
||||||
#endif
|
|
||||||
#ifdef _USE_DRZ80
|
#ifdef _USE_DRZ80
|
||||||
memset(&drZ80, 0, 0x54);
|
memset(&drZ80, 0, 0x54);
|
||||||
drZ80.Z80F = (1<<2); // set ZFlag
|
drZ80.Z80F = (1<<2); // set ZFlag
|
||||||
drZ80.Z80F2 = (1<<2); // set ZFlag
|
drZ80.Z80F2 = (1<<2); // set ZFlag
|
||||||
drZ80.Z80IX = 0xFFFF << 16;
|
drZ80.Z80IX = 0xFFFF << 16;
|
||||||
drZ80.Z80IY = 0xFFFF << 16;
|
drZ80.Z80IY = 0xFFFF << 16;
|
||||||
|
drZ80.Z80I = 0;
|
||||||
drZ80.Z80IM = 0; // 1?
|
drZ80.Z80IM = 0; // 1?
|
||||||
drZ80.z80irqvector = 0xff0000; // RST 38h
|
drZ80.z80irqvector = 0xff0000; // RST 38h
|
||||||
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
|
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
|
||||||
// drZ80 is locked in single bank
|
// drZ80 is locked in single bank
|
||||||
drZ80.Z80SP_BASE = ((PicoAHW & PAHW_SMS) ?
|
drz80_sp_base = (PicoAHW & PAHW_SMS) ? 0xc000 : 0x0000;
|
||||||
z80_read_map[0xc000 >> Z80_MEM_SHIFT] : z80_read_map[0]) << 1;
|
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
|
||||||
// drZ80.Z80SP = drZ80.z80_rebaseSP(0x2000); // 0xf000 ?
|
if (PicoAHW & PAHW_SMS)
|
||||||
|
drZ80.Z80SP = drZ80.Z80SP_BASE + 0xdff0; // simulate BIOS
|
||||||
#endif
|
#endif
|
||||||
#ifdef _USE_CZ80
|
#ifdef _USE_CZ80
|
||||||
Cz80_Reset(&CZ80);
|
Cz80_Reset(&CZ80);
|
||||||
Cz80_Set_Reg(&CZ80, CZ80_IX, 0xffff);
|
Cz80_Set_Reg(&CZ80, CZ80_IX, 0xffff);
|
||||||
Cz80_Set_Reg(&CZ80, CZ80_IY, 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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX TODO: should better use universal z80 save format
|
/* save state stuff */
|
||||||
PICO_INTERNAL void z80_pack(unsigned char *data)
|
static int z80_unpack_legacy(const void *data)
|
||||||
{
|
{
|
||||||
#if defined(_USE_MZ80)
|
#if defined(_USE_DRZ80)
|
||||||
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 (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
|
if (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
|
||||||
int pc, sp;
|
u32 pc, sp;
|
||||||
memcpy(&drZ80, data+4, 0x54);
|
memcpy(&drZ80, data+4, 0x54);
|
||||||
pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
|
pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
|
||||||
sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
|
sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
|
||||||
// update bases
|
// update bases
|
||||||
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
|
drz80_load_pcsp(pc, sp);
|
||||||
if (drZ80.Z80PC & (1<<31)) {
|
return 0;
|
||||||
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?
|
|
||||||
}
|
}
|
||||||
#elif defined(_USE_CZ80)
|
#elif defined(_USE_CZ80)
|
||||||
if (*(int *)data == 0x00007a43) { // "Cz" save?
|
if (*(int *)data == 0x00007a43) { // "Cz" save?
|
||||||
memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
|
memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
|
||||||
Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
|
Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
|
||||||
} else {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
int z80_unpack(const void *data)
|
||||||
|
{
|
||||||
|
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_reset();
|
||||||
z80_int();
|
z80_int();
|
||||||
}
|
return -1;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void z80_exit(void)
|
void z80_exit(void)
|
||||||
{
|
{
|
||||||
#if defined(_USE_MZ80)
|
|
||||||
mz80shutdown();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void z80_debug(char *dstr)
|
void z80_debug(char *dstr)
|
||||||
{
|
{
|
||||||
#if defined(_USE_DRZ80)
|
#if defined(_USE_DRZ80)
|
||||||
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
|
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
|
||||||
|
|
|
@ -25,13 +25,13 @@ endif
|
||||||
|
|
||||||
# === Pico core ===
|
# === Pico core ===
|
||||||
# Pico
|
# Pico
|
||||||
OBJS += pico/area.o pico/cart.o pico/memory.o pico/pico.o pico/sek.o pico/z80if.o \
|
OBJS += pico/state.o pico/cart.o pico/memory.o pico/pico.o pico/sek.o pico/z80if.o \
|
||||||
pico/videoport.o pico/draw2.o pico/draw.o pico/mode4.o pico/sms.o \
|
pico/videoport.o pico/draw2.o pico/draw.o pico/mode4.o pico/sms.o \
|
||||||
pico/misc.o pico/eeprom.o pico/patch.o pico/debug.o
|
pico/misc.o pico/eeprom.o pico/patch.o pico/debug.o
|
||||||
# CD
|
# CD
|
||||||
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \
|
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \
|
||||||
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \
|
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \
|
||||||
pico/cd/area.o pico/cd/misc.o pico/cd/pcm.o pico/cd/buffering.o
|
pico/cd/misc.o pico/cd/pcm.o pico/cd/buffering.o
|
||||||
# 32X
|
# 32X
|
||||||
OBJS += pico/32x/32x.o pico/32x/memory.o pico/32x/draw.o pico/32x/pwm.o
|
OBJS += pico/32x/32x.o pico/32x/memory.o pico/32x/draw.o pico/32x/pwm.o
|
||||||
# Pico
|
# Pico
|
||||||
|
@ -62,11 +62,6 @@ OBJS += cpu/fame/famec.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# --- Z80 ---
|
# --- Z80 ---
|
||||||
ifeq "$(use_mz80)" "1"
|
|
||||||
DEFINES += _USE_MZ80
|
|
||||||
OBJS += cpu/mz80/mz80.o
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
ifeq "$(use_drz80)" "1"
|
ifeq "$(use_drz80)" "1"
|
||||||
DEFINES += _USE_DRZ80
|
DEFINES += _USE_DRZ80
|
||||||
OBJS += cpu/DrZ80/drz80.o
|
OBJS += cpu/DrZ80/drz80.o
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
#include <revision.h>
|
#include <revision.h>
|
||||||
|
|
||||||
#include <pico/pico_int.h>
|
#include <pico/pico.h>
|
||||||
#include <pico/patch.h>
|
#include <pico/patch.h>
|
||||||
|
|
||||||
static char static_buff[64];
|
static char static_buff[64];
|
||||||
|
@ -1039,34 +1039,22 @@ static void state_check_slots(void)
|
||||||
|
|
||||||
static void draw_savestate_bg(int slot)
|
static void draw_savestate_bg(int slot)
|
||||||
{
|
{
|
||||||
struct PicoVideo tmp_pv;
|
|
||||||
unsigned short tmp_cram[0x40];
|
|
||||||
unsigned short tmp_vsram[0x40];
|
|
||||||
void *tmp_vram;
|
|
||||||
const char *fname;
|
const char *fname;
|
||||||
|
void *tmp_state;
|
||||||
|
|
||||||
fname = emu_get_save_fname(1, 0, slot);
|
fname = emu_get_save_fname(1, 0, slot);
|
||||||
if (!fname) return;
|
if (!fname)
|
||||||
|
return;
|
||||||
|
|
||||||
tmp_vram = malloc(sizeof(Pico.vram));
|
tmp_state = PicoTmpStateSave();
|
||||||
if (tmp_vram == NULL) return;
|
|
||||||
|
|
||||||
memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));
|
PicoStateLoadGfx(fname);
|
||||||
memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));
|
|
||||||
memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));
|
|
||||||
memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));
|
|
||||||
|
|
||||||
PicoStateLoadVDP(fname);
|
|
||||||
|
|
||||||
/* do a frame and fetch menu bg */
|
/* do a frame and fetch menu bg */
|
||||||
pemu_forced_frame(POPT_EN_SOFTSCALE);
|
pemu_forced_frame(POPT_EN_SOFTSCALE);
|
||||||
menu_enter(1);
|
menu_enter(1);
|
||||||
|
|
||||||
memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));
|
PicoTmpStateRestore(tmp_state);
|
||||||
memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));
|
|
||||||
memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));
|
|
||||||
memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));
|
|
||||||
free(tmp_vram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_savestate_menu(int menu_sel, int is_loading)
|
static void draw_savestate_menu(int menu_sel, int is_loading)
|
||||||
|
@ -1105,6 +1093,7 @@ static int menu_loop_savestate(int is_loading)
|
||||||
static int menu_sel = 10;
|
static int menu_sel = 10;
|
||||||
int menu_sel_max = 10;
|
int menu_sel_max = 10;
|
||||||
unsigned long inp = 0;
|
unsigned long inp = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
state_check_slots();
|
state_check_slots();
|
||||||
|
|
||||||
|
@ -1134,15 +1123,18 @@ static int menu_loop_savestate(int is_loading)
|
||||||
state_slot = menu_sel;
|
state_slot = menu_sel;
|
||||||
if (emu_save_load_game(is_loading, 0)) {
|
if (emu_save_load_game(is_loading, 0)) {
|
||||||
me_update_msg(is_loading ? "Load failed" : "Save failed");
|
me_update_msg(is_loading ? "Load failed" : "Save failed");
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
ret = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
if (inp & PBTN_MBACK)
|
if (inp & PBTN_MBACK)
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------- key config --------------
|
// -------------- key config --------------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue