From 3bb967da255cc4ccd92a2168b1d6ed13546f3cee Mon Sep 17 00:00:00 2001 From: libretroadmin Date: Mon, 9 Sep 2024 04:11:18 +0200 Subject: [PATCH] [PATCH] Add savestate handling Some notes to consider: - consider this wip. some vars might not be necessary. - only for C68K cpu core - minimally tested. it works on HD files, and multi-disks but have not tested on anything that switches to another disk yet or drive letter. - M3U/CMD platlist format is necessary to keep track of what content the state is for (filename for .statex tracking for example). Switching disk or switching to another game through ingame menu will break currently loaded state. - in core is use to run in content-less mode, the savestate will be universal or system state (PX68K.state) and will not be based on what content is loaded. - MIDI: Loading patchsets and other midi params from a state file is not implemented. It may take a while to refresh instruments sets until next time MIDI sends new data. Its also required that only load a state after selecting the correct MIDI device from the ingame menu. - requires new px68k_libretro.info file, with savestate support enabled --- Makefile.common | 2 + Makefile.libretro | 3 +- fmgen/fmg_wrap.cpp | 33 ++- fmgen/fmg_wrap.h | 1 + fmgen/fmgen.cpp | 108 ++++++++- fmgen/fmgen.h | 17 +- fmgen/fmtimer.cpp | 21 ++ fmgen/fmtimer.h | 6 +- fmgen/opm.cpp | 53 ++++ fmgen/opm.h | 2 + libretro.c | 127 +++++++++- libretro/common.h | 3 + libretro/dswin.c | 14 ++ libretro/dswin.h | 1 + libretro/state.c | 519 ++++++++++++++++++++++++++++++++++++++++ libretro/state.h | 69 ++++++ libretro/state_inline.h | 22 ++ libretro/timer.c | 4 +- libretro/timer.h | 3 + m68000/m68000.c | 57 +++++ m68000/m68000.h | 1 + x68k/adpcm.c | 39 +++ x68k/adpcm.h | 1 + x68k/bg.c | 38 +++ x68k/bg.h | 2 + x68k/crtc.c | 39 +++ x68k/crtc.h | 1 + x68k/dmac.c | 135 +++++++++-- x68k/dmac.h | 1 + x68k/fdc.c | 34 +++ x68k/fdc.h | 1 + x68k/fdd.c | 20 ++ x68k/fdd.h | 1 + x68k/gvram.c | 25 +- x68k/gvram.h | 1 + x68k/ioc.c | 15 ++ x68k/ioc.h | 1 + x68k/irqh.c | 14 ++ x68k/irqh.h | 1 + x68k/mfp.c | 18 ++ x68k/mfp.h | 1 + x68k/midi.c | 39 +++ x68k/midi.h | 1 + x68k/palette.c | 17 ++ x68k/palette.h | 1 + x68k/pia.c | 17 ++ x68k/pia.h | 1 + x68k/rtc.c | 18 ++ x68k/rtc.h | 1 + x68k/sasi.c | 27 +++ x68k/sasi.h | 1 + x68k/scc.c | 25 ++ x68k/scc.h | 1 + x68k/sram.c | 15 ++ x68k/sram.h | 1 + x68k/sysport.c | 17 ++ x68k/sysport.h | 1 + x68k/tvram.c | 21 +- x68k/tvram.h | 1 + x68k/x68kmemory.h | 2 +- 60 files changed, 1614 insertions(+), 47 deletions(-) create mode 100644 libretro/state.c create mode 100644 libretro/state.h create mode 100644 libretro/state_inline.h diff --git a/Makefile.common b/Makefile.common index ba4ace1..e9243d4 100644 --- a/Makefile.common +++ b/Makefile.common @@ -69,6 +69,7 @@ SOURCES_C += \ $(CORE_DIR)/libretro/dosio.c \ $(CORE_DIR)/libretro/fake.c \ $(CORE_DIR)/libretro/peace.c \ + $(CORE_DIR)/libretro/state.c \ $(CORE_DIR)/libretro.c SOURCES_CXX += \ @@ -84,6 +85,7 @@ SOURCES_C += \ $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \ $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \ $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \ + $(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \ $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \ $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \ $(LIBRETRO_COMM_DIR)/file/file_path.c \ diff --git a/Makefile.libretro b/Makefile.libretro index 165c4c8..026aba4 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -426,7 +426,8 @@ WARNINGS := FLAGS += -D__LIBRETRO__ $(ENDIANNESS_DEFINES) $(WARNINGS) $(fpic) CXXFLAGS += $(FLAGS) $(CPU_FLAGS) -fpermissive -CFLAGS += $(FLAGS) -std=c99 $(CPU_FLAGS) -D_GNU_SOURCE +#CFLAGS += $(FLAGS) -std=c99 $(CPU_FLAGS) -D_GNU_SOURCE +CFLAGS += $(FLAGS) $(CPU_FLAGS) $(TARGET): $(OBJECTS) ifeq ($(STATIC_LINKING), 1) diff --git a/fmgen/fmg_wrap.cpp b/fmgen/fmg_wrap.cpp index 843edd2..a01b71c 100644 --- a/fmgen/fmg_wrap.cpp +++ b/fmgen/fmg_wrap.cpp @@ -21,10 +21,15 @@ public: virtual ~MyOPM() {} void WriteIO(uint32_t adr, uint8_t data); void Count2(uint32_t clock); + private: virtual void Intr(bool); + +public: int CurReg; uint32_t CurCount; + + int StateAction(StateMem *sm, int load, int data_only); }; @@ -33,6 +38,22 @@ MyOPM::MyOPM() CurReg = 0; } +int MyOPM::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVARN(CurReg, "CurReg"), + SFVARN(CurCount, "CurCount"), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "MYOPM", false); + ret &= FM::OPM::StateAction(sm, load, data_only); + + return(1); +} + void MyOPM::WriteIO(uint32_t adr, uint8_t data) { if( adr&1 ) @@ -52,7 +73,6 @@ void MyOPM::Intr(bool f) if ( f ) ::MFP_Int(12); } - void MyOPM::Count2(uint32_t clock) { CurCount += clock; @@ -60,9 +80,16 @@ void MyOPM::Count2(uint32_t clock) CurCount %= 10; } - static MyOPM* opm = NULL; +int OPM_StateAction(StateMem *sm, int load, int data_only) +{ + if (opm) + return opm->StateAction(sm, load, data_only); + + return 1; +} + int OPM_Init(int clock) { opm = new MyOPM(); @@ -121,7 +148,7 @@ void OPM_SetVolume(uint8_t vol) // ---------------------------------------------------------- -// ---------------------------- YMF288 (満開版ま〜きゅり〜) +// ---------------------------- YMF288 (満開版ま~きゅり~) // ---------------------------------------------------------- // TODO : ROMEOの288を叩くの diff --git a/fmgen/fmg_wrap.h b/fmgen/fmg_wrap.h index 6b96d8e..fa6e38c 100644 --- a/fmgen/fmg_wrap.h +++ b/fmgen/fmg_wrap.h @@ -11,6 +11,7 @@ void FASTCALL OPM_Write(uint32_t r, uint8_t v); uint8_t FASTCALL OPM_Read(void); void FASTCALL OPM_Timer(uint32_t step); void OPM_SetVolume(uint8_t vol); +int OPM_StateAction(StateMem *sm, int load, int data_only); int M288_Init(int clock, const char* path); void M288_Cleanup(void); diff --git a/fmgen/fmgen.cpp b/fmgen/fmgen.cpp index 8b91e96..e59e8c5 100644 --- a/fmgen/fmgen.cpp +++ b/fmgen/fmgen.cpp @@ -222,6 +222,26 @@ void MakeLFOTable() } } +// +// +// +int Chip::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT ChipStateRegs[] = + { + SFVAR(ratio_), + SFVAR(aml_), + SFVAR(pml_), + SFVAR(pmv_), + SFVAR(optype_), + SFARRAY32(multable_, 4 * 16), + + SFEND + }; + + return PX68KSS_StateAction(sm, load, data_only, ChipStateRegs, "CHIP", false); +} + // --------------------------------------------------------------------------- // チップ内で共通な部分 @@ -266,6 +286,60 @@ bool FM::Operator::tablehasmade = false; uint32_t FM::Operator::sinetable[1024]; int32_t FM::Operator::cltable[FM_CLENTS]; +int Operator::StateAction(StateMem *sm, int load, int data_only, const char *sname) +{ + SFORMAT StateRegs[] = + { + SFVAR(out_), + SFVAR(out2_), + SFVAR(dp_), + SFVAR(detune_), + SFVAR(detune2_), + SFVAR(multiple_), + SFVAR(pg_count_), + SFVAR(pg_diff_), + SFVAR(pg_diff_lfo_), + SFVAR(type_), + SFVAR(bn_), + SFVAR(eg_level_), + SFVAR(eg_level_on_next_phase_), + SFVAR(eg_count_), + SFVAR(eg_count_diff_), + SFVAR(eg_out_), + SFVAR(tl_out_), + SFVAR(eg_rate_), + SFVAR(eg_curve_count_), + SFVAR(ssg_offset_), + SFVAR(ssg_vector_), + SFVAR(ssg_phase_), + SFVAR(key_scale_rate_), + SFVAR(eg_phase_), + SFVAR(ms_), + SFVAR(tl_), + SFVAR(tl_latch_), + SFVAR(ar_), + SFVAR(dr_), + SFVAR(sr_), + SFVAR(sl_), + SFVAR(rr_), + SFVAR(ks_), + SFVAR(ssg_type_), + SFVAR(keyon_), + SFVAR(amon_), + SFVAR(param_changed_), + SFVAR(mute_), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, sname, false); + + if (load) + ams_ = amtable[type_][amon_ ? (ms_ >> 4) & 3 : 0]; + + return ret; +} + // 構築 FM::Operator::Operator() : chip_(0) @@ -681,7 +755,6 @@ int Channel4::kftable[64]; bool Channel4::tablehasmade = false; - Channel4::Channel4() { if (!tablehasmade) @@ -691,6 +764,39 @@ Channel4::Channel4() pms = pmtable[0][0]; } +int Channel4::StateAction(StateMem *sm, int load, int data_only, const char *sname) +{ + SFORMAT StateRegs[] = + { + SFVAR(fb), + SFVAR(algo_), + SFARRAY32(buf, 4), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, sname, false); + + for (int i = 0; i < 4; i++) + { + char tmpstr[10] = "x"; + char tmpstr2[5] = "OPx"; + tmpstr2[2] = '0' + i; + strcpy(tmpstr, sname); + strcat(tmpstr, tmpstr2); + + ret &= op[i].StateAction(sm, load, data_only, tmpstr); + } + + if (load) + { + SetAlgorithm(algo_); + pms = pmtable[op[0].type_][op[0].ms_ & 7]; + } + + return ret; +} + void Channel4::MakeTable() { // 100/64 cent = 2^(i*100/64*1200) diff --git a/fmgen/fmgen.h b/fmgen/fmgen.h index 3e599da..5172668 100644 --- a/fmgen/fmgen.h +++ b/fmgen/fmgen.h @@ -32,7 +32,8 @@ namespace FM // Types ---------------------------------------------------------------- typedef int32_t ISample; - enum OpType { TYPE_N = 0, TYPE_M = 1 }; + enum OpType { TYPE_N = 0, TYPE_M = 1 }; + enum EGPhase { NEXT, ATTACK, DECAY, SUSTAIN, RELEASE, OFF }; void StoreSample(ISample& dest, int data); @@ -75,6 +76,9 @@ namespace FM void Mute(bool); int Out() { return out_; } + + int StateAction(StateMem *sm, int load, int data_only, const char *sname); + private: Chip* chip_; ISample out_, out2_; @@ -92,8 +96,6 @@ namespace FM int32_t pg_diff_lfo_; // Phase 差分値 >> x // Envelop Generator --------------------------------------------------- - enum EGPhase { NEXT, ATTACK, DECAY, SUSTAIN, RELEASE, OFF }; - void EGCalc(); void EGStep(); void ShiftPhase(EGPhase nextphase); @@ -101,7 +103,7 @@ namespace FM void SetEGRate(uint32_t); void EGUpdate(); ISample LogToLin(uint32_t a); - + OpType type_; // OP の種類 (M, N...) uint32_t bn_; // Block/Note int eg_level_; // EG の出力値 @@ -182,6 +184,8 @@ namespace FM void SetMS(uint32_t ms); void Mute(bool); + int StateAction(StateMem *mem, int load, int data_only, const char *sname); + private: static const uint8_t fbtable[8]; uint32_t fb; @@ -189,8 +193,9 @@ namespace FM int* in[3]; // 各 OP の入力ポインタ int* out[3]; // 各 OP の出力ポインタ int* pms; - int algo_; + Chip* chip_; + int algo_; static void MakeTable(); @@ -218,6 +223,8 @@ namespace FM int GetPMV() { return pmv_; } uint32_t GetRatio() { return ratio_; } + int StateAction(StateMem *sm, int load, int data_pnly); + private: void MakeTable(); diff --git a/fmgen/fmtimer.cpp b/fmgen/fmtimer.cpp index 35a67b3..f2a29a3 100644 --- a/fmgen/fmtimer.cpp +++ b/fmgen/fmtimer.cpp @@ -10,6 +10,27 @@ using namespace FM; +int Timer::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(status), + SFVAR(regtc), + + SFVARN(regta[0], "regta0"), + SFVARN(regta[1], "regta1"), + SFVAR(timera), + SFVAR(timera_count), + SFVAR(timerb), + SFVAR(timerb_count), + SFVAR(timer_step), + + SFEND + }; + + return PX68KSS_StateAction(sm, load, data_only, StateRegs, "TIMER", false); +} + // --------------------------------------------------------------------------- // タイマー制御 // diff --git a/fmgen/fmtimer.h b/fmgen/fmtimer.h index 0afaa13..f9ffa02 100644 --- a/fmgen/fmtimer.h +++ b/fmgen/fmtimer.h @@ -16,6 +16,7 @@ namespace FM public: void Reset(); bool Count(int32_t us); + int StateAction(StateMem *st, int load, int data_only); protected: virtual void SetStatus(uint32_t bit) = 0; @@ -25,12 +26,13 @@ namespace FM void SetTimerA(uint32_t addr, uint32_t data); void SetTimerB(uint32_t data); void SetTimerControl(uint32_t data); - + uint8_t status; uint8_t regtc; - + private: virtual void TimerA() {} + uint8_t regta[2]; int32_t timera, timera_count; diff --git a/fmgen/opm.cpp b/fmgen/opm.cpp index 759c3b7..fc9e9ea 100644 --- a/fmgen/opm.cpp +++ b/fmgen/opm.cpp @@ -29,6 +29,59 @@ OPM::OPM() } } +int OPM::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT OPMStateRegs[] = + { + SFVAR(fmvolume), + SFVAR(clock), + SFVAR(rate), + + SFVAR(pmd), + SFVAR(amd), + SFVAR(lfocount), + SFVAR(lfodcount), + + SFVAR(lfo_count_), + SFVAR(lfo_count_diff_), + SFVAR(lfo_step_), + SFVAR(lfo_count_prev_), + + SFVAR(lfowaveform), + SFVAR(rateratio), + SFVAR(noise), + SFVAR(noisecount), + SFVAR(noisedelta), + + SFVAR(lfofreq), + SFVAR(status), + SFVAR(reg01), + + SFARRAY(kc, 8), + SFARRAY(kf, 8), + SFARRAY(pan, 8), + + SFEND + }; + + int ret = Timer::StateAction(sm, load, data_only); + + ret &= PX68KSS_StateAction(sm, load, data_only, OPMStateRegs, "OPM", false); + + ret &= ch[0].StateAction(sm, load, data_only, "SCH0"); + ret &= ch[1].StateAction(sm, load, data_only, "SCH1"); + ret &= ch[2].StateAction(sm, load, data_only, "SCH2"); + ret &= ch[3].StateAction(sm, load, data_only, "SCH3"); + ret &= ch[4].StateAction(sm, load, data_only, "SCH4"); + ret &= ch[5].StateAction(sm, load, data_only, "SCH5"); + ret &= ch[6].StateAction(sm, load, data_only, "SCH6"); + ret &= ch[7].StateAction(sm, load, data_only, "SCH7"); + + ret &= chip.StateAction(sm, load, data_only); + + return ret; +} + // --------------------------------------------------------------------------- // 初期化 // diff --git a/fmgen/opm.h b/fmgen/opm.h index a0786b2..df840d0 100644 --- a/fmgen/opm.h +++ b/fmgen/opm.h @@ -33,6 +33,8 @@ namespace FM void SetVolume(int db); void SetChannelMask(uint32_t mask); + + int StateAction(StateMem *sm, int load, int data_only); private: virtual void Intr(bool) {} diff --git a/libretro.c b/libretro.c index 0f34aa1..009dfea 100644 --- a/libretro.c +++ b/libretro.c @@ -781,12 +781,12 @@ static int WinX68k_Init(void) MEM = (uint8_t*)malloc(MEM_SIZE); FONT = (uint8_t*)malloc(0xc0000); - if (MEM) + if (MEM) memset(MEM, 0, MEM_SIZE); if (MEM && FONT && IPL) { - m68000_init(); + /* m68000_init(); */ return 1; } return 0; @@ -976,12 +976,17 @@ static int pmain(int argc, char *argv[]) StatBar_Show(Config.WindowFDDStat); WinUI_Init(); +#if 0 + /* TODO: CLean this up */ if (!WinX68k_Init()) { WinX68k_Cleanup(); WinDraw_Cleanup(); return 1; } +#endif + + m68000_init(); if (!WinX68k_LoadROMs()) { @@ -995,7 +1000,10 @@ static int pmain(int argc, char *argv[]) WinDraw_Init(); ADPCM_Init(); +#if 0 + /* TODO: CLean this up */ OPM_Init(4000000/*3579545*/); +#endif #ifndef NO_MERCURY Mcry_Init(winx68k_dir); #endif @@ -1093,7 +1101,7 @@ run_pmain: if (PARAMCOUNT) xargv_cmd[PARAMCOUNT - 2] = NULL; - + return 0; } @@ -1558,9 +1566,108 @@ static void setup_frame_time_cb(void) } /* TODO/FIXME - implement savestates */ -size_t retro_serialize_size(void) { return 0; } -bool retro_serialize(void *data, size_t size) { return false; } -bool retro_unserialize(const void *data, size_t size) { return false; } +int StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAYN(MEM, MEM_SIZE, "RAM"), + SFARRAYN(SRAM, 16384, "SRAM"), + SFVAR(ICount), + SFVAR(ClkUsed), + SFVAR(VLINE), + SFVAR(VLINE_TOTAL), + + SFVAR(tick), + SFVAR(timercnt), + + SFEND + }; + + int ret = 0, count = 0; + + ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "MAIN", false); + ret &= m68000_StateAction(sm, load, data_only); + ret &= GVRAM_StateAction(sm, load, data_only); + ret &= TVRAM_StateAction(sm, load, data_only); + ret &= CRTC_StateAction(sm, load, data_only); + ret &= Pal_StateAction(sm, load, data_only); + ret &= BG_StateAction(sm, load, data_only); + ret &= DMAC_StateAction(sm, load, data_only); + ret &= MFP_StateAction(sm, load, data_only); + ret &= IRQH_StateAction(sm, load, data_only); + ret &= SCC_StateAction(sm, load, data_only); + ret &= FDC_StateAction(sm, load, data_only); + ret &= FDD_StateAction(sm, load, data_only); + ret &= SASI_StateAction(sm, load, data_only); + + ret &= RTC_StateAction(sm, load, data_only); + ret &= PIA_StateAction(sm, load, data_only); + ret &= SysPort_StateAction(sm, load, data_only); + ret &= IOC_StateAction(sm, load, data_only); + ret &= SRAM_StateAction(sm, load, data_only); + + /* sound-related states */ + ret &= dswin_StateAction(sm, load, data_only); + ret &= ADPCM_StateAction(sm, load, data_only); + ret &= MIDI_StateAction(sm, load, data_only); + ret &= OPM_StateAction(sm, load, data_only); + + return ret; +} + +size_t retro_serialize_size(void) +{ + StateMem st; + + st.data = NULL; + st.loc = 0; + st.len = 0; + st.malloced = 0; + st.initial_malloc = 0; + + if (!PX68KSS_SaveSM(&st, 0, 0, NULL, NULL, NULL)) + return 0; + + free(st.data); + + return st.len; +} + +bool retro_serialize(void *data, size_t size) +{ + StateMem st; + bool ret = false; + uint8_t *_dat = (uint8_t*)malloc(size); + + if (!_dat) + return false; + + st.data = _dat; + st.loc = 0; + st.len = 0; + st.malloced = size; + st.initial_malloc = 0; + + ret = PX68KSS_SaveSM(&st, 0, 0, NULL, NULL, NULL); + + memcpy(data, st.data, size); + free(st.data); + + return ret; +} + +bool retro_unserialize(const void *data, size_t size) +{ + StateMem st; + + st.data = (uint8_t*)data; + st.loc = 0; + st.len = size; + st.malloced = 0; + st.initial_malloc = 0; + + return PX68KSS_LoadSM(&st, 0, 0); +} /* TODO/FIXME - implement cheats */ void retro_cheat_reset(void) { } @@ -1582,6 +1689,14 @@ bool retro_load_game(const struct retro_game_info *info) return false; } + /* alloc memory pointers */ + if (!WinX68k_Init()) + return false; + + /* alloc OPM-related pointers */ + if (!OPM_Init(4000000/*3579545*/)) + return false; + return true; } diff --git a/libretro/common.h b/libretro/common.h index d15de50..0ad3ebb 100644 --- a/libretro/common.h +++ b/libretro/common.h @@ -8,6 +8,9 @@ #include extern retro_log_printf_t log_cb; +#include "state.h" +#include "state_inline.h" + #undef FASTCALL #define FASTCALL diff --git a/libretro/dswin.c b/libretro/dswin.c index 1164121..c70abd2 100644 --- a/libretro/dswin.c +++ b/libretro/dswin.c @@ -41,6 +41,20 @@ uint8_t *pbsp = pcmbuffer; uint8_t *pbrp = pcmbuffer, *pbwp = pcmbuffer; uint8_t *pbep = &pcmbuffer[PCMBUF_SIZE]; +int dswin_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(snd_precounter), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_DSND", false); + + return ret; +} + void DSound_Play(void) { ADPCM_SetVolume((uint8_t)Config.PCM_VOL); diff --git a/libretro/dswin.h b/libretro/dswin.h index eb0579d..5b95dc2 100644 --- a/libretro/dswin.h +++ b/libretro/dswin.h @@ -10,5 +10,6 @@ void DSound_Send0(int32_t clock); int audio_samples_avail(void); void audio_samples_discard(int discard); void raudio_callback(void *userdata, unsigned char *stream, int len); +int dswin_StateAction(StateMem *sm, int load, int data_only); #endif /* _DSWIN_H */ diff --git a/libretro/state.c b/libretro/state.c new file mode 100644 index 0000000..e86f209 --- /dev/null +++ b/libretro/state.c @@ -0,0 +1,519 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" +#include "state.h" + +#define SSEEK_END 2 +#define SSEEK_CUR 1 +#define SSEEK_SET 0 + +#define RLSB PX68KSTATE_RLSB //0x80000000 + +/* Forward declaration */ +int StateAction(StateMem *sm, int load, int data_only); + +static INLINE void PX68K_en32lsb(uint8_t *buf, uint32_t morp) +{ + buf[0]=morp; + buf[1]=morp>>8; + buf[2]=morp>>16; + buf[3]=morp>>24; +} + +static INLINE uint32_t PX68K_de32lsb(const uint8_t *morp) +{ + return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)); +} + +#ifdef MSB_FIRST +static INLINE void Endian_A64_Swap(void *src, uint32_t nelements) +{ + uint32_t i; + uint8_t *nsrc = (uint8_t *)src; + + for(i = 0; i < nelements; i++) + { + unsigned z; + uint8_t *base = &nsrc[i * 8]; + + for(z = 0; z < 4; z++) + { + uint8_t tmp = base[z]; + + base[z] = base[7 - z]; + base[7 - z] = tmp; + } + } +} + +static INLINE void Endian_A32_Swap(void *src, uint32_t nelements) +{ + uint32_t i; + uint8_t *nsrc = (uint8_t *)src; + + for(i = 0; i < nelements; i++) + { + uint8_t tmp1 = nsrc[i * 4]; + uint8_t tmp2 = nsrc[i * 4 + 1]; + + nsrc[i * 4] = nsrc[i * 4 + 3]; + nsrc[i * 4 + 1] = nsrc[i * 4 + 2]; + + nsrc[i * 4 + 2] = tmp2; + nsrc[i * 4 + 3] = tmp1; + } +} + +void Endian_A16_Swap(void *src, uint32_t nelements) +{ + uint32_t i; + uint8_t *nsrc = (uint8_t *)src; + + for(i = 0; i < nelements; i++) + { + uint8_t tmp = nsrc[i * 2]; + + nsrc[i * 2] = nsrc[i * 2 + 1]; + nsrc[i * 2 + 1] = tmp; + } +} + +static INLINE void FlipByteOrder(uint8_t *src, uint32_t count) +{ + uint8_t *start=src; + uint8_t *end=src+count-1; + + if((count&1) || !count) + return; /* This shouldn't happen. */ + + count >>= 1; + + while(count--) + { + uint8_t tmp; + + tmp=*end; + *end=*start; + *start=tmp; + end--; + start++; + } +} +#endif + +static int32_t smem_read(StateMem *st, void *buffer, uint32_t len) +{ + if ((len + st->loc) > st->len) + return 0; + + memcpy(buffer, st->data + st->loc, len); + st->loc += len; + + return(len); +} + +static int32_t smem_write(StateMem *st, void *buffer, uint32_t len) +{ + if ((len + st->loc) > st->malloced) + { + uint32_t newsize = (st->malloced >= 32768) ? st->malloced : (st->initial_malloc ? st->initial_malloc : 32768); + + while(newsize < (len + st->loc)) + newsize *= 2; + st->data = (uint8_t *)realloc(st->data, newsize); + st->malloced = newsize; + } + + memcpy(st->data + st->loc, buffer, len); + st->loc += len; + + if (st->loc > st->len) + st->len = st->loc; + + return(len); +} + +static int32_t smem_seek(StateMem *st, uint32_t offset, int whence) +{ + switch(whence) + { + case SSEEK_SET: + st->loc = offset; + break; + case SSEEK_END: + st->loc = st->len - offset; + break; + case SSEEK_CUR: + st->loc += offset; + break; + } + + if(st->loc > st->len) + { + st->loc = st->len; + return(-1); + } + + return(0); +} + +static int smem_write32le(StateMem *st, uint32_t b) +{ + uint8_t s[4]; + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; + return((smem_write(st, s, 4)<4)?0:4); +} + +static int smem_read32le(StateMem *st, uint32_t *b) +{ + uint8_t s[4]; + + if(smem_read(st, s, 4) < 4) + return(0); + + *b = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); + + return(4); +} + +static bool SubWrite(StateMem *st, SFORMAT *sf) +{ + /* Size can sometimes be zero, so also check for the text name. + * These two should both be zero only at the end of a struct. */ + while(sf->size || sf->name) + { + int32_t bytesize; + char nameo[1 + 256]; + + if(!sf->size || !sf->v) + { + sf++; + continue; + } + + /* Link to another struct. */ + if(sf->size == (uint32_t)~0) + { + if(!SubWrite(st, (SFORMAT *)sf->v)) + return(0); + + sf++; + continue; + } + + bytesize = sf->size; + nameo[0] = strlcpy(nameo + 1, sf->name, 256); + + smem_write(st, nameo, 1 + nameo[0]); + smem_write32le(st, bytesize); + +#ifdef MSB_FIRST + /* Flip the byte order... */ + if(sf->flags & PX68KSTATE_BOOL) { } + else if(sf->flags & PX68KSTATE_RLSB64) + Endian_A64_Swap(sf->v, bytesize / sizeof(uint64_t)); + else if(sf->flags & PX68KSTATE_RLSB32) + Endian_A32_Swap(sf->v, bytesize / sizeof(uint32_t)); + else if(sf->flags & PX68KSTATE_RLSB16) + Endian_A16_Swap(sf->v, bytesize / sizeof(uint16_t)); + else if(sf->flags & RLSB) + FlipByteOrder((uint8_t*)sf->v, bytesize); +#endif + + /* Special case for the evil bool type, + * to convert bool to 1-byte elements. + * Don't do it if we're only saving the raw data. */ + if(sf->flags & PX68KSTATE_BOOL) + { + int32_t bool_monster; + for (bool_monster = 0; bool_monster < bytesize; bool_monster++) + { + uint8_t tmp_bool = ((bool *)sf->v)[bool_monster]; + smem_write(st, &tmp_bool, 1); + } + } + else + smem_write(st, (uint8_t *)sf->v, bytesize); + +#ifdef MSB_FIRST + /* Now restore the original byte order. */ + if(sf->flags & PX68KSTATE_BOOL) + { + + } + else if(sf->flags & PX68KSTATE_RLSB64) + Endian_A64_Swap(sf->v, bytesize / sizeof(uint64_t)); + else if(sf->flags & PX68KSTATE_RLSB32) + Endian_A32_Swap(sf->v, bytesize / sizeof(uint32_t)); + else if(sf->flags & PX68KSTATE_RLSB16) + Endian_A16_Swap(sf->v, bytesize / sizeof(uint16_t)); + else if(sf->flags & RLSB) + FlipByteOrder((uint8_t*)sf->v, bytesize); +#endif + sf++; + } + + return true; +} + +static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf) +{ + int32_t data_start_pos; + int32_t end_pos; + + uint8_t sname_tmp[32]; + size_t sname_len = strlen(sname); + + memset(sname_tmp, 0, sizeof(sname_tmp)); + memcpy((char *)sname_tmp, sname, (sname_len < 32) ? sname_len : 32); + + smem_write(st, sname_tmp, 32); + + smem_write32le(st, 0); // We'll come back and write this later. + + data_start_pos = st->loc; + + if(!SubWrite(st, sf)) + return(0); + + end_pos = st->loc; + + smem_seek(st, data_start_pos - 4, SSEEK_SET); + smem_write32le(st, end_pos - data_start_pos); + smem_seek(st, end_pos, SSEEK_SET); + + return(end_pos - data_start_pos); +} + +static SFORMAT *FindSF(const char *name, SFORMAT *sf) +{ + /* Size can sometimes be zero, so also check for the text name. + * These two should both be zero only at the end of a struct. */ + while(sf->size || sf->name) + { + if(!sf->size || !sf->v) + { + sf++; + continue; + } + + /* Link to another SFORMAT structure. */ + if (sf->size == (uint32_t)~0) + { + SFORMAT *temp_sf = FindSF(name, (SFORMAT*)sf->v); + if (temp_sf) + return temp_sf; + } + else + { + if (!strcmp(sf->name, name)) + return sf; + } + + sf++; + } + + return NULL; +} + +static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size) +{ + int temp = st->loc; + + while (st->loc < (temp + size)) + { + /* Don't change to char unless cast + * toa[0] to unsigned to smem_read() + * and other places. */ + uint8_t toa[1 + 256]; + uint32_t recorded_size = 0; /* In bytes */ + SFORMAT *tmp = NULL; + + if(smem_read(st, toa, 1) != 1) + return(0); + + if(smem_read(st, toa + 1, toa[0]) != toa[0]) + return 0; + + toa[1 + toa[0]] = 0; + + smem_read32le(st, &recorded_size); + tmp = FindSF((char*)toa + 1, sf); + + if(tmp) + { + uint32_t expected_size = tmp->size; /* In bytes */ + + if(recorded_size != expected_size) + { + if(smem_seek(st, recorded_size, SSEEK_CUR) < 0) + return(0); + } + else + { + smem_read(st, (uint8_t *)tmp->v, expected_size); + + if(tmp->flags & PX68KSTATE_BOOL) + { + int32_t bool_monster; + /* Converting downwards is necessary + * for the case of sizeof(bool) > 1 */ + for(bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--) + ((bool *)tmp->v)[bool_monster] = ((uint8_t *)tmp->v)[bool_monster]; + } + +#ifdef MSB_FIRST + if(tmp->flags & PX68KSTATE_RLSB64) + Endian_A64_Swap(tmp->v, expected_size / sizeof(uint64_t)); + else if(tmp->flags & PX68KSTATE_RLSB32) + Endian_A32_Swap(tmp->v, expected_size / sizeof(uint32_t)); + else if(tmp->flags & PX68KSTATE_RLSB16) + Endian_A16_Swap(tmp->v, expected_size / sizeof(uint16_t)); + else if(tmp->flags & RLSB) + FlipByteOrder((uint8_t*)tmp->v, expected_size); +#endif + } + } + else + { + if(smem_seek(st, recorded_size, SSEEK_CUR) < 0) + return(0); + } + } + + return 1; +} + +static int PX68KSS_StateAction_internal(StateMem *st, int load, int data_only, + struct SSDescriptor *section) +{ + if(load) + { + char sname[32]; + + uint32_t tmp_size = 0; + int found = 0; + uint32_t total = 0; + + while(smem_read(st, (uint8_t *)sname, 32) == 32) + { + if(smem_read32le(st, &tmp_size) != 4) + { + return(0); + } + + total += tmp_size + 32 + 4; + + // Yay, we found the section + if(!strncmp(sname, section->name, 32)) + { + if(!ReadStateChunk(st, section->sf, tmp_size)) + { + return(0); + } + found = 1; + break; + } + else + { + if(smem_seek(st, tmp_size, SSEEK_CUR) < 0) + { + return(0); + } + } + } + + if(smem_seek(st, -total, SSEEK_CUR) < 0) + { + return(0); + } + + if(!found) // Not found. We are sad! + { + return(0); + } + } + else + { + if(!WriteStateChunk(st, section->name, section->sf)) + return(0); + } + + return(1); +} + +int PX68KSS_StateAction(void *st_p, int load, int data_only, SFORMAT *sf, const char *name, bool optional) +{ + struct SSDescriptor love; + StateMem *st = (StateMem*)st_p; + + love.sf = sf; + love.name = name; + + return PX68KSS_StateAction_internal(st, load, 0, &love); +} + +int PX68KSS_SaveSM(void *st_p, int a, int b, const void*c, const void*d, const void*e) +{ + uint32_t sizy; + uint8_t header[32]; + StateMem *st = (StateMem*)st_p; + static const char *header_magic = "PX68KSVST"; + + memset(header, 0, sizeof(header)); + memcpy(header, header_magic, 9); + + PX68K_en32lsb(header + 16, PX68K_VERSION_NUMERIC); + smem_write(st, header, 32); + + if(!StateAction(st, 0, 0)) + return(0); + + sizy = st->loc; + smem_seek(st, 16 + 4, SSEEK_SET); + smem_write32le(st, sizy); + + return(1); +} + +int PX68KSS_LoadSM(void *st_p, int a, int b) +{ + uint8_t header[32]; + uint32_t stateversion; + StateMem *st = (StateMem*)st_p; + + smem_read(st, header, 32); + + if(memcmp(header, "PX68KSVESTATE", 13) && memcmp(header, "PX68KSVST", 9)) + return(0); + + stateversion = PX68K_de32lsb(header + 16); + + return(StateAction(st, stateversion, 0)); +} diff --git a/libretro/state.h b/libretro/state.h new file mode 100644 index 0000000..d7f259e --- /dev/null +++ b/libretro/state.h @@ -0,0 +1,69 @@ +#ifndef _STATE_H +#define _STATE_H + +#include + +#include +#include + +#define PX68K_VERSION_MAJOR 0 +#define PX68K_VERSION_MINOR 15 +#define PX68K_VERSION_PATCH 0 + +#define PX68K_VERSION_NUMERIC ((PX68K_VERSION_MAJOR * 10000) + (PX68K_VERSION_MINOR * 100) + (PX68K_VERSION_PATCH)) + +typedef struct +{ + uint8_t *data; + uint32_t loc; + uint32_t len; + uint32_t malloced; + uint32_t initial_malloc; /* A setting! */ +} StateMem; + +#ifdef __cplusplus +extern "C" { +#endif + +int PX68KSS_SaveSM(void *st, int, int, const void*, const void*, const void*); +int PX68KSS_LoadSM(void *st, int, int); + +/* Flag for a single, >= 1 byte native-endian variable */ +#define PX68KSTATE_RLSB 0x80000000 +/* 32-bit native-endian elements */ +#define PX68KSTATE_RLSB32 0x40000000 +/* 16-bit native-endian elements */ +#define PX68KSTATE_RLSB16 0x20000000 +/* 64-bit native-endian elements */ +#define PX68KSTATE_RLSB64 0x10000000 + +#define PX68KSTATE_BOOL 0x08000000 + +typedef struct +{ + void *v; /* Pointer to the variable/array */ + uint32_t size; /* Length, in bytes, of the data to be saved EXCEPT: + * In the case of PX68KSTATE_BOOL, it is the number + * of bool elements to save(bool is not always 1-byte). + * + * If 0, the subchunk isn't saved. + */ + uint32_t flags; /* Flags */ + const char *name; /* Name */ +} SFORMAT; + +/* State-Section Descriptor */ +struct SSDescriptor +{ + + SFORMAT *sf; + const char *name; +}; + +int PX68KSS_StateAction(void *st, int load, int data_only, SFORMAT *sf, const char *name, bool optional); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/state_inline.h b/libretro/state_inline.h new file mode 100644 index 0000000..cbfbe03 --- /dev/null +++ b/libretro/state_inline.h @@ -0,0 +1,22 @@ +#ifndef _STATE_IN_HPP +#define _STATE_IN_HPP + +#define SFVARN_BOOL(x, n) { &(x), 1, PX68KSTATE_RLSB | PX68KSTATE_BOOL, n } +#define SFVARN(x, n) { &(x), (uint32_t)sizeof(x), PX68KSTATE_RLSB, n } +#define SFVAR(x) SFVARN((x), #x) + +#define SFARRAYN(x, l, n) { (x), (uint32_t)(l), 0, n } +#define SFARRAY(x, l) SFARRAYN((x), (l), #x) + +#define SFARRAY16N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint16_t)), PX68KSTATE_RLSB16, n } +#define SFARRAY16(x, l) SFARRAY16N((x), (l), #x) + +#define SFARRAY32N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint32_t)), PX68KSTATE_RLSB32, n } +#define SFARRAY32(x, l) SFARRAY32N((x), (l), #x) + +#define SFARRAY64N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint64_t)), PX68KSTATE_RLSB64, n } +#define SFARRAY64(x, l) SFARRAY64N((x), (l), #x) + +#define SFEND { 0, 0, 0, 0 } + +#endif diff --git a/libretro/timer.c b/libretro/timer.c index 75638d0..18294f6 100644 --- a/libretro/timer.c +++ b/libretro/timer.c @@ -5,7 +5,8 @@ #include "crtc.h" #include "mfp.h" -static uint32_t tick = 0; +uint32_t tick = 0; +uint32_t timercnt = 0; /* Get elapsed time from libretro frontend by way of its frame time callback, * if available. Only provides per frame granularity, enough for this case @@ -27,7 +28,6 @@ void Timer_Init(void) uint16_t Timer_GetCount(void) { - static uint32_t timercnt = 0; uint32_t ticknow = timeGetUsec(); uint32_t dif = ticknow-tick; uint32_t TIMEBASE = ((CRTC_Regs[0x29]&0x10)?VSYNC_HIGH:VSYNC_NORM); diff --git a/libretro/timer.h b/libretro/timer.h index cb8c8dd..e0b3a2c 100644 --- a/libretro/timer.h +++ b/libretro/timer.h @@ -1,6 +1,9 @@ #ifndef _WINXL_TIMER_H #define _WINXL_TIMER_H +extern uint32_t tick; +extern uint32_t timercnt; + void Timer_Init(void); uint16_t Timer_GetCount(void); diff --git a/m68000/m68000.c b/m68000/m68000.c index 965262b..64cfb7e 100644 --- a/m68000/m68000.c +++ b/m68000/m68000.c @@ -22,6 +22,63 @@ struct Cyclone m68k; int m68000_ICountBk; int ICount; +int m68000_StateAction(StateMem *sm, int load, int data_only) +{ + int ret = 0; + uint32_t pc = 0; + SFORMAT StateRegs[] = + { + SFVARN(C68K.D[0], "D0"), + SFVARN(C68K.D[1], "D1"), + SFVARN(C68K.D[2], "D2"), + SFVARN(C68K.D[3], "D3"), + SFVARN(C68K.D[4], "D4"), + SFVARN(C68K.D[5], "D5"), + SFVARN(C68K.D[6], "D6"), + SFVARN(C68K.D[7], "D7"), + + SFVARN(C68K.A[0], "A0"), + SFVARN(C68K.A[1], "A1"), + SFVARN(C68K.A[2], "A2"), + SFVARN(C68K.A[3], "A3"), + SFVARN(C68K.A[4], "A4"), + SFVARN(C68K.A[5], "A5"), + SFVARN(C68K.A[6], "A6"), + SFVARN(C68K.A[7], "A7"), + + SFVARN(C68K.flag_C, "flag_C"), + SFVARN(C68K.flag_V, "flag_V"), + SFVARN(C68K.flag_notZ, "flag_notZ"), + SFVARN(C68K.flag_X, "flag_X"), + SFVARN(C68K.flag_I, "flag_I"), + SFVARN(C68K.flag_S, "flag_S"), + + SFVARN(C68K.USP, "USP"), + + SFVARN(pc, "PC"), + + SFVARN(C68K.Status, "status"), + SFVARN(C68K.IRQLine, "IRQLine"), + + SFVARN(C68K.CycleToDo, "CycleToDo"), + SFVARN(C68K.CycleIO, "CycleIO"), + SFVARN(C68K.CycleSup, "CycleSup"), + SFVARN(C68K.dirty1, "dirtyflag"), + + SFEND + }; + + if (!load) + pc = m68000_get_reg(M68K_PC); + + ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_CPU", false); + + if (load) + m68000_set_reg(M68K_PC, pc); + + return ret; +} + #if defined (HAVE_CYCLONE) unsigned int read8(unsigned int a) { diff --git a/m68000/m68000.h b/m68000/m68000.h index c7c0bee..7ac40fc 100644 --- a/m68000/m68000.h +++ b/m68000/m68000.h @@ -42,6 +42,7 @@ int m68000_execute(int cycles); void m68000_set_irq_line(int irqline, int state); uint32_t m68000_get_reg(int regnum); void m68000_set_reg(int regnum, uint32_t val); +int m68000_StateAction(StateMem *sm, int load, int data_only); #ifdef SAVE_STATE STATE_SAVE( m68000 ); diff --git a/x68k/adpcm.c b/x68k/adpcm.c index 41608d8..871d91a 100644 --- a/x68k/adpcm.c +++ b/x68k/adpcm.c @@ -59,6 +59,45 @@ static int OutsIp[4]; static int OutsIpR[4]; static int OutsIpL[4]; +int ADPCM_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + /* TODO: Some of the vars might not be necessary */ + SFARRAY16(ADPCM_BufL, 96000), + SFARRAY16(ADPCM_BufR, 96000), + + SFVAR(ADPCM_VolumeShift), + SFVAR(ADPCM_WrPtr), + SFVAR(ADPCM_RdPtr), + + SFVAR(ADPCM_ClockRate), + SFVAR(ADPCM_Count), + + SFVAR(ADPCM_Step), + SFVAR(ADPCM_Out), + SFVAR(ADPCM_Playing), + SFVAR(ADPCM_Clock), + SFVAR(ADPCM_PreCounter), + SFVAR(ADPCM_DifBuf), + + SFVAR(ADPCM_Pan), + SFVAR(OldR), + SFVAR(OldL), + SFARRAY32(Outs, 8), + SFARRAY32(OutsIp, 4), + SFARRAY32(OutsIpR, 4), + SFARRAY32(OutsIpL, 4), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_ADPC", false); + + return ret; +} + + static void ADPCM_InitTable(void) { int step, n; diff --git a/x68k/adpcm.h b/x68k/adpcm.h index 7d2f8af..365a888 100644 --- a/x68k/adpcm.h +++ b/x68k/adpcm.h @@ -14,5 +14,6 @@ void ADPCM_SetPan(int n); void ADPCM_SetClock(int n); void ADPCM_Init(void); +int ADPCM_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_ADPCM_H */ diff --git a/x68k/bg.c b/x68k/bg.c index 15a51d0..8d2d67d 100644 --- a/x68k/bg.c +++ b/x68k/bg.c @@ -34,6 +34,44 @@ uint16_t BG_PriBuf[1600]; uint32_t VLINEBG = 0; +int BG_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(BG, 0x8000), + SFARRAY(Sprite_Regs, 0x800), + SFARRAY(BG_Regs, 0x12), + + SFVAR(BG_CHREND), + SFVAR(BG_BG0TOP), + SFVAR(BG_BG0END), + SFVAR(BG_BG1TOP), + SFVAR(BG_BG1END), + SFVAR(BG_CHRSIZE), + SFVAR(BG_AdrMask), + SFVAR(BG0ScrollX), + SFVAR(BG0ScrollY), + SFVAR(BG1ScrollX), + SFVAR(BG1ScrollY), + + SFARRAY(BGCHR8, (8 * 8 * 256)), + SFARRAY(BGCHR16, (16 * 16 * 256)), + SFARRAY16(BG_PriBuf, 1600), + SFARRAY16(BG_LineBuf, 1600), + + SFVAR(BG_HAdjust), + SFVAR(BG_VLINE), + SFVAR(VLINEBG), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_BG", false); + + return ret; +} + + void BG_Init(void) { uint32_t i; diff --git a/x68k/bg.h b/x68k/bg.h index 8fa6b16..40e5bb4 100644 --- a/x68k/bg.h +++ b/x68k/bg.h @@ -21,4 +21,6 @@ void FASTCALL BG_Write(uint32_t adr, uint8_t data); void FASTCALL BG_DrawLine(int opaq, int gd); +int BG_StateAction(StateMem *sm, int load, int data_only); + #endif /* _WINX68K_BG_H */ diff --git a/x68k/crtc.c b/x68k/crtc.c index baa6e0e..3b2e25b 100644 --- a/x68k/crtc.c +++ b/x68k/crtc.c @@ -37,6 +37,45 @@ uint8_t CRTC_RCFlag[2] = {0, 0}; int HSYNC_CLK = 324; extern int VID_MODE, CHANGEAV_TIMING; +int CRTC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(CRTC_Regs, 48), + SFVAR(CRTC_Mode), + SFVAR(TextDotX), + SFVAR(TextDotY), + SFVAR(CRTC_VSTART), + SFVAR(CRTC_VEND), + SFVAR(CRTC_HSTART), + SFVAR(CRTC_HEND), + SFVAR(TextScrollX), + SFVAR(TextScrollY), + SFARRAY32(GrphScrollX, 4), + SFARRAY32(GrphScrollY, 4), + + SFVAR(CRTC_FastClr), + SFVAR(CRTC_FastClrMask), + SFVAR(CRTC_IntLine), + SFVAR(CRTC_VStep), + + SFARRAY(CRTC_RCFlag, 2), + + SFVAR(HSYNC_CLK), + + /* video control regs */ + SFARRAY(VCReg0, 2), + SFARRAY(VCReg1, 2), + SFARRAY(VCReg2, 2), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_CRTC_VCTRL", false); + + return ret; +} + void CRTC_RasterCopy(void) { uint32_t line = (((uint32_t)CRTC_Regs[0x2d])<<2); diff --git a/x68k/crtc.h b/x68k/crtc.h index ea1c6e2..a7ab45d 100644 --- a/x68k/crtc.h +++ b/x68k/crtc.h @@ -36,5 +36,6 @@ void FASTCALL CRTC_Write(uint32_t adr, uint8_t data); uint8_t FASTCALL VCtrl_Read(uint32_t adr); void FASTCALL VCtrl_Write(uint32_t adr, uint8_t data); +int CRTC_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_CRTC_H */ diff --git a/x68k/dmac.c b/x68k/dmac.c index da1e06a..a99d9b5 100644 --- a/x68k/dmac.c +++ b/x68k/dmac.c @@ -24,6 +24,97 @@ static uint32_t FASTCALL DMA_Int(uint8_t irq); DMA[ch].CCR &= 0x7f; \ DMAINT(ch) +int DMAC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVARN(DMA[0].CSR, "CSR0"), + SFVARN(DMA[0].CER, "CER0"), + SFVARN(DMA[0].DCR, "DCR0"), + SFVARN(DMA[0].OCR, "OCR0"), + SFVARN(DMA[0].SCR, "SCR0"), + SFVARN(DMA[0].CCR, "CCR0"), + SFVARN(DMA[0].MTC, "MTC0"), + SFVARN(DMA[0].MAR, "MAR0"), + SFVARN(DMA[0].DAR, "DAR0"), + SFVARN(DMA[0].BTC, "BTC0"), + SFVARN(DMA[0].BAR, "BAR0"), + SFVARN(DMA[0].NIV, "NIV0"), + SFVARN(DMA[0].EIV, "EIV0"), + SFVARN(DMA[0].MFC, "MFC0"), + SFVARN(DMA[0].CPR, "CPR0"), + SFVARN(DMA[0].DFC, "DFC0"), + SFVARN(DMA[0].BFC, "BFC0"), + SFVARN(DMA[0].GCR, "GCR0"), + + SFVARN(DMA[1].CSR, "CSR1"), + SFVARN(DMA[1].CER, "CER1"), + SFVARN(DMA[1].DCR, "DCR1"), + SFVARN(DMA[1].OCR, "OCR1"), + SFVARN(DMA[1].SCR, "SCR1"), + SFVARN(DMA[1].CCR, "CCR1"), + SFVARN(DMA[1].MTC, "MTC1"), + SFVARN(DMA[1].MAR, "MAR1"), + SFVARN(DMA[1].DAR, "DAR1"), + SFVARN(DMA[1].BTC, "BTC1"), + SFVARN(DMA[1].BAR, "BAR1"), + SFVARN(DMA[1].NIV, "NIV1"), + SFVARN(DMA[1].EIV, "EIV1"), + SFVARN(DMA[1].MFC, "MFC1"), + SFVARN(DMA[1].CPR, "CPR1"), + SFVARN(DMA[1].DFC, "DFC1"), + SFVARN(DMA[1].BFC, "BFC1"), + SFVARN(DMA[1].GCR, "GCR1"), + + SFVARN(DMA[2].CSR, "CSR2"), + SFVARN(DMA[2].CER, "CER2"), + SFVARN(DMA[2].DCR, "DCR2"), + SFVARN(DMA[2].OCR, "OCR2"), + SFVARN(DMA[2].SCR, "SCR2"), + SFVARN(DMA[2].CCR, "CCR2"), + SFVARN(DMA[2].MTC, "MTC2"), + SFVARN(DMA[2].MAR, "MAR2"), + SFVARN(DMA[2].DAR, "DAR2"), + SFVARN(DMA[2].BTC, "BTC2"), + SFVARN(DMA[2].BAR, "BAR2"), + SFVARN(DMA[2].NIV, "NIV2"), + SFVARN(DMA[2].EIV, "EIV2"), + SFVARN(DMA[2].MFC, "MFC2"), + SFVARN(DMA[2].CPR, "CPR2"), + SFVARN(DMA[2].DFC, "DFC2"), + SFVARN(DMA[2].BFC, "BFC2"), + SFVARN(DMA[2].GCR, "GCR2"), + + SFVARN(DMA[3].CSR, "CSR3"), + SFVARN(DMA[3].CER, "CER3"), + SFVARN(DMA[3].DCR, "DCR3"), + SFVARN(DMA[3].OCR, "OCR3"), + SFVARN(DMA[3].SCR, "SCR3"), + SFVARN(DMA[3].CCR, "CCR3"), + SFVARN(DMA[3].MTC, "MTC3"), + SFVARN(DMA[3].MAR, "MAR3"), + SFVARN(DMA[3].DAR, "DAR3"), + SFVARN(DMA[3].BTC, "BTC3"), + SFVARN(DMA[3].BAR, "BAR3"), + SFVARN(DMA[3].NIV, "NIV3"), + SFVARN(DMA[3].EIV, "EIV3"), + SFVARN(DMA[3].MFC, "MFC3"), + SFVARN(DMA[3].CPR, "CPR3"), + SFVARN(DMA[3].DFC, "DFC3"), + SFVARN(DMA[3].BFC, "BFC3"), + SFVARN(DMA[3].GCR, "GCR3"), + + SFVAR(DMA_IntCH), + SFVAR(DMA_LastInt), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_DMAC", false); + + return ret; +} + static int ADPCM_IsReady(void) { return 1; } static int DMA_DummyIsReady(void) { return 0; } @@ -63,7 +154,7 @@ uint8_t FASTCALL DMA_Read(uint32_t adr) int ch = (adr >> 6) & 0x03; if (adr >= 0xe84100) - return 0; /* 真真真 */ + return 0; switch (off) { @@ -146,7 +237,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) uint8_t old = 0; if (adr >= 0xe84100) - return; /* 真真真 */ + return; switch (off) { @@ -172,7 +263,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) case 0x07: old = DMA[ch].CCR; - DMA[ch].CCR = (data & 0xef) | (DMA[ch].CCR & 0x80); /* CCR�STR真真真真真真 */ + DMA[ch].CCR = (data & 0xef) | (DMA[ch].CCR & 0x80); /* CCR STR cannot be dropped by writing */ if ((data & 0x10) && (DMA[ch].CCR & 0x80)) { /* Software Abort */ @@ -181,16 +272,16 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) } if (data & 0x20) /* Halt */ { - /* 真真真真�Nemesis'90真真真真 */ + /* Should be correct, but Nemesis'90 will not work properly with it so... */ /* DMA[ch].CSR &= 0xf7; */ break; } if (data & 0x80) { - /* 真真 */ + /* Start DMA */ if (old & 0x20) { - /* Halt真 */ + /* Halt release */ DMA[ch].CSR |= 0x08; DMA_Exec(ch); } @@ -198,14 +289,14 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) { if (DMA[ch].CSR & 0xf8) { - /* 真真真真 */ + /* Timing errors */ DMAERR(ch, 0x02) break; } DMA[ch].CSR |= 0x08; if ((DMA[ch].OCR & 8) /*&&(!DMA[ch].MTC)*/) { - /* 真真真真真真真 */ + /* Array/Link Array Chain */ DMA[ch].MAR = dma_readmem24_dword(DMA[ch].BAR) & 0xffffff; DMA[ch].MTC = dma_readmem24_word(DMA[ch].BAR + 4); if (DMA[ch].OCR & 4) @@ -217,7 +308,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) DMA[ch].BAR += 6; if (!DMA[ch].BTC) { - /* 真真真真真 */ + /* This is also a counting error */ DMAERR(ch, 0x0f) break; } @@ -225,12 +316,12 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) } if (!DMA[ch].MTC) { - /* 真真真� */ + /* Counting error */ DMAERR(ch, 0x0d) break; } DMA[ch].CER = 0x00; - DMA_Exec(ch); /* 真真真真真真真真真真真真真真真真真真真 */ + DMA_Exec(ch); /* Since you may need to check the counter immediately after starting, run it for a little while. */ } } if ((data & 0x40) && (!DMA[ch].MTC)) @@ -244,7 +335,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) } else if (DMA[ch].OCR & 8) { - /* 真真真真真真真 */ + /* Array/Link Array Chain */ DMAERR(ch, 0x01) } else @@ -256,7 +347,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) DMA[ch].BTC = 0; if (!DMA[ch].MAR) { - DMA[ch].CSR |= 0x40; /* 真真真真真真真真 ? */ + DMA[ch].CSR |= 0x40; /* Block transfer end bit/interrupt? */ DMAINT(ch) break; } @@ -271,7 +362,7 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data) } else { - /* �Active真CNT真真真真真真真 */ + /* The CNT bit in non-active mode indicates an operation timing error */ DMAERR(ch, 0x02) } } @@ -463,9 +554,9 @@ int FASTCALL DMA_Exec(int ch) } DMA[ch].MTC--; - if ( !DMA[ch].MTC ) { /* 指定分のバイト数転送終了 */ - if ( DMA[ch].OCR&8 ) { /* チェインモードで動いている場合 */ - if ( DMA[ch].OCR&4 ) { /* リンクアレイチェイン */ + if ( !DMA[ch].MTC ) { /* Transfer of specified number of bytes completed */ + if ( DMA[ch].OCR&8 ) { /* If running in chained mode */ + if ( DMA[ch].OCR&4 ) { /* If running in chained mode */ if ( DMA[ch].BAR ) { DMA[ch].MAR = dma_readmem24_dword(DMA[ch].BAR); DMA[ch].MTC = dma_readmem24_word(DMA[ch].BAR+4); @@ -482,9 +573,9 @@ int FASTCALL DMA_Exec(int ch) break; } } - } else { /* アレイチェイン */ + } else { /* Array chain */ DMA[ch].BTC--; - if ( DMA[ch].BTC ) { /* 次のブロックがある */ + if ( DMA[ch].BTC ) { /* Next block exists */ DMA[ch].MAR = dma_readmem24_dword(DMA[ch].BAR); DMA[ch].MTC = dma_readmem24_word(DMA[ch].BAR+4); DMA[ch].BAR += 6; @@ -501,9 +592,9 @@ int FASTCALL DMA_Exec(int ch) } } } - } else { /* 通常モード(1ブロックのみ)終了 */ - if ( DMA[ch].CCR&0x40 ) { /* Countinuous動作中 */ - DMA[ch].CSR |= 0x40; /* ブロック転送終了ビット/割り込み */ + } else { /* Normal mode (only one block) finished */ + if ( DMA[ch].CCR&0x40 ) { /* Countinuous action */ + DMA[ch].CSR |= 0x40; /* Block transfer end bit/interrupt */ DMAINT(ch) if ( DMA[ch].BAR ) { DMA[ch].MAR = DMA[ch].BAR; diff --git a/x68k/dmac.h b/x68k/dmac.h index d032ab9..b6898a0 100644 --- a/x68k/dmac.h +++ b/x68k/dmac.h @@ -45,5 +45,6 @@ void FASTCALL DMA_Write(uint32_t adr, uint8_t data); int FASTCALL DMA_Exec(int ch); void DMA_Init(void); +int DMAC_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_DMAC_H */ diff --git a/x68k/fdc.c b/x68k/fdc.c index e5653ce..13a1fb8 100644 --- a/x68k/fdc.c +++ b/x68k/fdc.c @@ -84,6 +84,40 @@ typedef struct { static FDC fdc; +int FDC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(fdc.cmd), + + SFVAR(fdc.cyl), + SFVAR(fdc.drv), + SFVAR(fdc.ready), + SFVAR(fdc.ctrl), + SFVAR(fdc.wexec), + + SFVAR(fdc.rdptr), + SFVAR(fdc.wrptr), + SFVAR(fdc.rdnum), + SFVAR(fdc.wrnum), + SFVAR(fdc.bufnum), + SFVAR(fdc.st0), + SFVAR(fdc.st1), + SFVAR(fdc.st2), + + SFARRAY(fdc.RspBuf, 10), + SFARRAY(fdc.PrmBuf, 10), + SFARRAY(fdc.DataBuf, 0x8000), + SFARRAY(fdc.ScanBuf, 0x8000), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_FDC", false); + + return ret; +} + #define US(p) (p->us&3) #define HD(p) ((p->us>>2)&1) diff --git a/x68k/fdc.h b/x68k/fdc.h index 61e59cf..0cb8a8a 100644 --- a/x68k/fdc.h +++ b/x68k/fdc.h @@ -10,5 +10,6 @@ void FASTCALL FDC_Write(uint32_t adr, uint8_t data); int16_t FDC_Flush(void); void FDC_SetForceReady(int n); int FDC_IsDataReady(void); +int FDC_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_FDC_H */ diff --git a/x68k/fdd.c b/x68k/fdd.c index 54227db..178e278 100644 --- a/x68k/fdd.c +++ b/x68k/fdd.c @@ -37,6 +37,26 @@ static int (*GetCurrentID[4])(int, FDCID*) = { 0, XDF_GetCur int FDD_IsReading = 0; +int FDD_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY32(fdd.SetDelay, 4), + SFARRAY32(fdd.Types, 4), + SFARRAY32(fdd.ROnly, 4), + SFARRAY32(fdd.EMask, 4), + SFARRAY32(fdd.Blink, 4), + + SFVAR(fdd.Access), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_FDD", false); + + return ret; +} + static void ConvertCapital(char* buf) { for ( ; *buf; buf++) diff --git a/x68k/fdd.h b/x68k/fdd.h index d02d711..387e549 100644 --- a/x68k/fdd.h +++ b/x68k/fdd.h @@ -39,6 +39,7 @@ void FDD_SetReadOnly(int drv); void FDD_SetEMask(int drive, int emask); void FDD_SetAccess(int drive); void FDD_SetBlink(int drive, int blink); +int FDD_StateAction(StateMem *sm, int load, int data_only); /* Misc: Used to trigger rumble when FDD is reading data. * Reset at every frame */ diff --git a/x68k/gvram.c b/x68k/gvram.c index 9ce59c7..3d24d2d 100644 --- a/x68k/gvram.c +++ b/x68k/gvram.c @@ -14,11 +14,30 @@ uint8_t GVRAM[0x80000]; uint16_t Grp_LineBuf[1024]; -uint16_t Grp_LineBufSP[1024]; /* 頗真真真真真真真真真綽� */ +uint16_t Grp_LineBufSP[1024]; /* �?真真真真真真真真真綽� */ uint16_t Grp_LineBufSP2[1024]; /* 真真真真真真真真水真真真真真真綽真真 */ static uint16_t Grp_LineBufSP_Tr[1024]; static uint16_t Pal16Adr[256]; /* 16bit color 真水真真真真真 */ +int GVRAM_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAYN(GVRAM, 524288, "MEM_GVRAM"), + SFARRAY16(Grp_LineBuf, 1024), + SFARRAY16(Grp_LineBufSP, 1024), + SFARRAY16(Grp_LineBufSP2, 1024), + SFARRAY16(Grp_LineBufSP_Tr, 1024), + SFARRAY16(Pal16Adr, 256), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_GVRAM", false); + + return ret; +} + #ifdef MSB_FIRST #define GET_WORD_W8(src) (*(uint16_t *)(src)) #else @@ -225,7 +244,7 @@ void FASTCALL GVRAM_Write(uint32_t adr, uint8_t data) /* - * 真推真真真真饋真真真真真� + * 真推真真真真?真真真真真� */ void Grp_DrawLine16(void) { @@ -513,7 +532,7 @@ void FASTCALL Grp_DrawLine4h(void) /* - * --- 真真真頗�Pri真真真真真真真真真真 --- + * --- 真真真�?�Pri真真真真真真真真真真 --- */ void FASTCALL Grp_DrawLine16SP(void) { diff --git a/x68k/gvram.h b/x68k/gvram.h index 6f226a7..0963179 100644 --- a/x68k/gvram.h +++ b/x68k/gvram.h @@ -27,5 +27,6 @@ void FASTCALL Grp_DrawLine4hSP(void); void FASTCALL Grp_DrawLine8TR(int page, int opaq); void FASTCALL Grp_DrawLine8TR_GT(int page, int opaq); void FASTCALL Grp_DrawLine4TR(uint32_t page, int opaq); +int GVRAM_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_GVRAM_H */ diff --git a/x68k/ioc.c b/x68k/ioc.c index 539fe7e..0af1b43 100644 --- a/x68k/ioc.c +++ b/x68k/ioc.c @@ -8,6 +8,21 @@ uint8_t IOC_IntStat = 0; uint8_t IOC_IntVect = 0; +int IOC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(IOC_IntStat), + SFVAR(IOC_IntVect), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_IOC", false); + + return ret; +} + void IOC_Init(void) { IOC_IntStat = 0; diff --git a/x68k/ioc.h b/x68k/ioc.h index 730298e..9d367ec 100644 --- a/x68k/ioc.h +++ b/x68k/ioc.h @@ -10,5 +10,6 @@ extern uint8_t IOC_IntVect; void IOC_Init(void); uint8_t FASTCALL IOC_Read(uint32_t adr); void FASTCALL IOC_Write(uint32_t adr, uint8_t data); +int IOC_StateAction(StateMem *sm, int load, int data_only); #endif /* WINX68K_IOC_H */ diff --git a/x68k/irqh.c b/x68k/irqh.c index fac8e58..13388ae 100644 --- a/x68k/irqh.c +++ b/x68k/irqh.c @@ -16,6 +16,20 @@ typedef int32_t FASTCALL C68K_INT_CALLBACK(int32_t level); static uint8_t IRQH_IRQ[8]; static void *IRQH_CallBack[8]; +int IRQH_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(IRQH_IRQ, 8), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_IRQH", false); + + return ret; +} + void IRQH_Init(void) { memset(IRQH_IRQ, 0, 8); diff --git a/x68k/irqh.h b/x68k/irqh.h index 28b524b..17cc454 100644 --- a/x68k/irqh.h +++ b/x68k/irqh.h @@ -7,5 +7,6 @@ void IRQH_Init(void); void IRQH_IRQCallBack(uint8_t irq); void IRQH_Int(uint8_t irq, void* handler); +int IRQH_StateAction(StateMem *sm, int load, int data_only); #endif /* WINX68K_IRQ_H */ diff --git a/x68k/mfp.c b/x68k/mfp.c index 0cb139b..bd1cbd0 100644 --- a/x68k/mfp.c +++ b/x68k/mfp.c @@ -16,6 +16,24 @@ static uint8_t Timer_Reload[4] = {0, 0, 0, 0}; static int32_t Timer_Tick[4] = {0, 0, 0, 0}; static const int Timer_Prescaler[8] = {1, 10, 25, 40, 125, 160, 250, 500}; +int MFP_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(MFP, 24), + SFVAR(LastKey), + SFARRAY(Timer_Reload, 4), + SFARRAY32(Timer_Tick, 4), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_MFP", false); + + return ret; +} + + uint32_t FASTCALL MFP_IntCallback(uint8_t irq) { uint8_t flag; diff --git a/x68k/mfp.h b/x68k/mfp.h index d775d2a..d100274 100644 --- a/x68k/mfp.h +++ b/x68k/mfp.h @@ -39,5 +39,6 @@ void FASTCALL MFP_Write(uint32_t adr, uint8_t data); void FASTCALL MFP_Timer(int32_t clock); void FASTCALL MFP_TimerA(void); void MFP_Int(int irq); +int MFP_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_MFP_H */ diff --git a/x68k/midi.c b/x68k/midi.c index b3ab0f9..a0c8fae 100644 --- a/x68k/midi.c +++ b/x68k/midi.c @@ -112,6 +112,45 @@ static uint8_t EXCV_XGRESET[] = { 0xf0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00 #define MIDIOUTS(a,b,c) (((size_t)c << 16) | ((size_t)b << 8) | (size_t)a) +int MIDI_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(MIDI_CTRL), + SFVAR(MIDI_POS), + SFVAR(MIDI_SYSCOUNT), + + SFVAR(MIDI_LAST), + SFARRAY(MIDI_BUF, 1024), + SFARRAY(MIDI_EXCVBUF, 1024), + + SFVAR(MIDI_RegHigh), + SFVAR(MIDI_Vector), + SFVAR(MIDI_IntEnable), + SFVAR(MIDI_IntVect), + SFVAR(MIDI_IntFlag), + SFVAR(MIDI_Buffered), + SFVAR(MIDI_BufTimer), + SFVAR(MIDI_R05), + SFVAR(MIDI_GTimerMax), + SFVAR(MIDI_MTimerMax), + SFVAR(MIDI_GTimerVal), + SFVAR(MIDI_MTimerVal), + SFVAR(MIDI_MODULE), + + SFARRAY(DelayBuf, ((4 + 1) * MIDIDELAYBUF)), + SFVAR(DBufPtrW), + SFVAR(DBufPtrR), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_MIDI", false); + + return ret; +} + + static uint32_t FASTCALL MIDI_Int(uint8_t irq) { IRQH_IRQCallBack(irq); diff --git a/x68k/midi.h b/x68k/midi.h index c0f8350..18b86e0 100644 --- a/x68k/midi.h +++ b/x68k/midi.h @@ -13,5 +13,6 @@ void FASTCALL MIDI_Timer(uint32_t clk); int MIDI_SetMimpiMap(char *filename); int MIDI_EnableMimpiDef(int enable); void MIDI_DelayOut(unsigned int delay); +int MIDI_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_MIDI_H */ diff --git a/x68k/palette.c b/x68k/palette.c index ab2f2c2..7cf582c 100644 --- a/x68k/palette.c +++ b/x68k/palette.c @@ -20,6 +20,23 @@ uint16_t Ibit; uint16_t Pal_HalfMask, Pal_Ix2; uint16_t Pal_R, Pal_G, Pal_B; +int Pal_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(Pal_Regs, 1024), + SFARRAY16(TextPal, 256), + SFARRAY16(GrphPal, 256), + SFARRAY16(Pal16, 65536), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_Palette", false); + + return ret; +} + void Pal_SetColor(void) { int i; diff --git a/x68k/palette.h b/x68k/palette.h index 4e51a09..11a0789 100644 --- a/x68k/palette.h +++ b/x68k/palette.h @@ -15,6 +15,7 @@ void Pal_Init(void); uint8_t FASTCALL Pal_Read(uint32_t adr); void FASTCALL Pal_Write(uint32_t adr, uint8_t data); void Pal_ChangeContrast(int num); +int Pal_StateAction(StateMem *sm, int load, int data_only); extern uint16_t Ibit, Pal_HalfMask, Pal_Ix2; diff --git a/x68k/pia.c b/x68k/pia.c index 081710b..c9d1d1a 100644 --- a/x68k/pia.c +++ b/x68k/pia.c @@ -17,6 +17,23 @@ typedef struct { static PIA pia; +int PIA_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(pia.PortA), + SFVAR(pia.PortB), + SFVAR(pia.PortC), + SFVAR(pia.Ctrl), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_PIA", false); + + return ret; +} + void PIA_Init(void) { pia.PortA = 0xff; diff --git a/x68k/pia.h b/x68k/pia.h index f58e89a..4a34ab9 100644 --- a/x68k/pia.h +++ b/x68k/pia.h @@ -7,5 +7,6 @@ void PIA_Init(void); uint8_t FASTCALL PIA_Read(uint32_t adr); void FASTCALL PIA_Write(uint32_t adr, uint8_t data); +int PIA_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_PIA_H */ diff --git a/x68k/rtc.c b/x68k/rtc.c index 1983fc4..1eba5e9 100644 --- a/x68k/rtc.c +++ b/x68k/rtc.c @@ -12,6 +12,24 @@ static uint8_t RTC_Bank = 0; static int RTC_Timer1 = 0; static int RTC_Timer16 = 0; +int RTC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAYN(RTC_Regs[0], 16, "RTCRegs0"), + SFARRAYN(RTC_Regs[1], 16, "RTCRegs1"), + SFVAR(RTC_Bank), /* never changed since alarm is not implemented, but whatever */ + SFVAR(RTC_Timer1), + SFVAR(RTC_Timer16), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_RTC", false); + + return ret; +} + void RTC_Init(void) { memset(&RTC_Regs[1][0], 0, 16); diff --git a/x68k/rtc.h b/x68k/rtc.h index 37a720d..f9fad63 100644 --- a/x68k/rtc.h +++ b/x68k/rtc.h @@ -7,5 +7,6 @@ void RTC_Init(void); uint8_t FASTCALL RTC_Read(uint32_t adr); void FASTCALL RTC_Write(uint32_t adr, uint8_t data); void RTC_Timer(int clock); +int RTC_StateAction(StateMem *sm, int load, int data_only); #endif /* _X68K_RTC_H */ diff --git a/x68k/sasi.c b/x68k/sasi.c index 173c936..2567edc 100644 --- a/x68k/sasi.c +++ b/x68k/sasi.c @@ -26,6 +26,33 @@ static uint8_t SASI_Error = 0; static uint8_t SASI_SenseStatBuf[4]; static uint8_t SASI_SenseStatPtr = 0; +int SASI_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY(SASI_Cmd, 6), + SFARRAY(SASI_Buf, 256), + SFVAR(SASI_Phase), + SFVAR(SASI_Sector), + SFVAR(SASI_Blocks), + SFVAR(SASI_CmdPtr), + SFVAR(SASI_Device), + SFVAR(SASI_Unit), + SFVAR(SASI_BufPtr), + SFVAR(SASI_RW), + SFVAR(SASI_Stat), + SFVAR(SASI_Error), + SFARRAY(SASI_SenseStatBuf, 4), + SFVAR(SASI_SenseStatPtr), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_SASI", false); + + return ret; +} + int SASI_IsReady(void) { if ( (SASI_Phase==2)||(SASI_Phase==3)||(SASI_Phase==9) ) diff --git a/x68k/sasi.h b/x68k/sasi.h index d98ff27..b386d36 100644 --- a/x68k/sasi.h +++ b/x68k/sasi.h @@ -8,5 +8,6 @@ void SASI_Init(void); uint8_t FASTCALL SASI_Read(uint32_t adr); void FASTCALL SASI_Write(uint32_t adr, uint8_t data); int SASI_IsReady(void); +int SASI_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_SASI_H */ diff --git a/x68k/scc.c b/x68k/scc.c index fe067ad..8df96af 100644 --- a/x68k/scc.c +++ b/x68k/scc.c @@ -21,6 +21,31 @@ static uint8_t SCC_Vector = 0; static uint8_t SCC_Dat[3] = {0, 0, 0}; static uint8_t SCC_DatNum = 0; +int SCC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(MouseX), + SFVAR(MouseY), + SFVAR(MouseSt), + + SFVAR(SCC_RegNumA), + SFVAR(SCC_RegSetA), + SFARRAY(SCC_RegsB, 16), + SFVAR(SCC_RegNumB), + SFVAR(SCC_RegSetB), + SFVAR(SCC_Vector), + SFARRAY(SCC_Dat, 3), + SFVAR(SCC_DatNum), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_SCC", false); + + return ret; +} + static uint32_t FASTCALL SCC_Int(uint8_t irq) { IRQH_IRQCallBack(irq); diff --git a/x68k/scc.h b/x68k/scc.h index 7e5fb77..4982c43 100644 --- a/x68k/scc.h +++ b/x68k/scc.h @@ -8,6 +8,7 @@ void SCC_IntCheck(void); void SCC_Init(void); uint8_t FASTCALL SCC_Read(uint32_t adr); void FASTCALL SCC_Write(uint32_t adr, uint8_t data); +int SCC_StateAction(StateMem *sm, int load, int data_only); extern int8_t MouseX; extern int8_t MouseY; diff --git a/x68k/sram.c b/x68k/sram.c index fda7e7b..cf100e4 100644 --- a/x68k/sram.c +++ b/x68k/sram.c @@ -13,6 +13,21 @@ static int write_enabled = 0; uint8_t SRAM[0x4000]; +int SRAM_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAYN(SRAM, 0x4000, "MEM_SRAM"), + SFVAR(write_enabled), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_SRAM", false); + + return ret; +} + void SRAM_VirusCheck(void) { if ( (cpu_readmem24_dword(0xed3f60)==0x60000002) diff --git a/x68k/sram.h b/x68k/sram.h index afaf9f4..a10ef31 100644 --- a/x68k/sram.h +++ b/x68k/sram.h @@ -14,5 +14,6 @@ void SRAM_WriteEnable(int enable); uint8_t FASTCALL SRAM_Read(uint32_t adr); void FASTCALL SRAM_Write(uint32_t adr, uint8_t data); +int SRAM_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_SRAM_H */ diff --git a/x68k/sysport.c b/x68k/sysport.c index 31f7e65..2a95c5b 100644 --- a/x68k/sysport.c +++ b/x68k/sysport.c @@ -18,6 +18,23 @@ typedef struct static SYSPORT sysport; +int SysPort_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(sysport.contrast), + SFVAR(sysport.monitor), + SFVAR(sysport.keyctrl), + SFVAR(sysport.cputype), + + SFEND + }; + + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_SysPort", false); + + return ret; +} + void SysPort_Init(void) { static uint8_t cputype[] = { diff --git a/x68k/sysport.h b/x68k/sysport.h index 13e168d..945e31f 100644 --- a/x68k/sysport.h +++ b/x68k/sysport.h @@ -9,5 +9,6 @@ extern uint8_t SysPort[7]; void SysPort_Init(void); uint8_t FASTCALL SysPort_Read(uint32_t adr); void FASTCALL SysPort_Write(uint32_t adr, uint8_t data); +int SysPort_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_SYSPORT_H */ diff --git a/x68k/tvram.c b/x68k/tvram.c index 732a282..c3fc800 100644 --- a/x68k/tvram.c +++ b/x68k/tvram.c @@ -14,10 +14,29 @@ uint8_t TVRAM[0x80000]; static uint8_t TextDrawWork[1024*1024]; uint8_t TextDirtyLine[1024]; +uint8_t Text_TrFlag[1024]; +/* pattern table */ static uint8_t TextDrawPattern[2048*4]; -uint8_t Text_TrFlag[1024]; +int TVRAM_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAYN(TVRAM, 524288, "MEM_TVRAM"), + SFARRAY(TextDrawWork, (1024 * 1024)), + SFARRAY(TextDirtyLine, 1024), + SFARRAY(Text_TrFlag, 1024), + + SFEND + }; + int ret = PX68KSS_StateAction(sm, load, data_only, StateRegs, "X68K_TVRAM", false); + + if (load) + TVRAM_SetAllDirty(); + + return ret; +} void TVRAM_SetAllDirty(void) { memset(TextDirtyLine, 1, 1024); } void TVRAM_Cleanup(void) { } diff --git a/x68k/tvram.h b/x68k/tvram.h index 43997b0..abe235a 100644 --- a/x68k/tvram.h +++ b/x68k/tvram.h @@ -17,5 +17,6 @@ uint8_t FASTCALL TVRAM_Read(uint32_t adr); void FASTCALL TVRAM_Write(uint32_t adr, uint8_t data); void FASTCALL TVRAM_RCUpdate(void); void FASTCALL Text_DrawLine(int opaq); +int TVRAM_StateAction(StateMem *sm, int load, int data_only); #endif /* _WINX68K_TVRAM_H */ diff --git a/x68k/x68kmemory.h b/x68k/x68kmemory.h index 17e41ec..53ff8d5 100644 --- a/x68k/x68kmemory.h +++ b/x68k/x68kmemory.h @@ -5,7 +5,7 @@ #include "../libretro/common.h" extern uint8_t* IPL; -extern uint8_t* MEM; +extern uint8_t* MEM; extern uint8_t* FONT; extern uint8_t SCSIIPL[0x2000]; extern uint8_t SRAM[0x4000];