From 4553d74106e0db869c9e80b8050a61b16aeb7310 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sat, 11 May 2013 18:52:19 +0000 Subject: [PATCH] saturn - fix a few savestate issues (that i caused in the first place, of course) and fix a possible problem with memory not being initialized. or maybe not. didn't actually solve any problems, la la la.... --- BizHawk.MultiClient/output/dll/libyabause.dll | Bin 563200 -> 563200 bytes yabause/src/scsp.c | 30 +- yabause/src/smpc.c | 1616 ++++++++--------- 3 files changed, 826 insertions(+), 820 deletions(-) diff --git a/BizHawk.MultiClient/output/dll/libyabause.dll b/BizHawk.MultiClient/output/dll/libyabause.dll index 0911a812d63f9db738a5f0a039ba19c4227080d9..07f41b4dff5c58110904d6bd5e901cc10dbaa45d 100644 GIT binary patch delta 23700 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

W=FE>ecFv>IdrI)o;`_ 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 delta 23497 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 diff --git a/yabause/src/scsp.c b/yabause/src/scsp.c index 6756ad93d5..458d2a927e 100644 --- a/yabause/src/scsp.c +++ b/yabause/src/scsp.c @@ -2842,6 +2842,8 @@ scsp_init (u8 *scsp_ram, void (*sint_hand)(u32), void (*mint_hand)(void)) scsp_shutdown (); + memset(&scsp, 0, sizeof(scsp)); + scsp_isr = &scsp_reg[0x0000]; scsp_ccr = &scsp_reg[0x0400]; scsp_dcr = &scsp_reg[0x0700]; @@ -3755,25 +3757,27 @@ M68KClearCodeBreakpoints () void StateFlatten(slot_t *s) { - s->buf8 = (s8*)(int)(s->buf8 - (s8*)scsp.scsp_ram); - s->buf16 = (s16*)(int)(s->buf16 - (s16*)scsp.scsp_ram); + if (s->buf8) + s->buf8 = (s8*)(int)(s->buf8 - (s8*)scsp.scsp_ram); + if (s->buf16) + s->buf16 = (s16*)(int)(s->buf16 - (s16*)scsp.scsp_ram); if (s->einc) s->einc = (s32*)(int)(s->einc - (s32*)s); if (s->arp == &scsp_null_rate[0]) s->arp = (s32*)(void*)0xdeadbeef; - else + else if (s->arp) s->arp = (s32*)(int)(s->arp - scsp_attack_rate); if (s->drp == &scsp_null_rate[0]) s->drp = (s32*)(void*)0xdeadbeef; - else + else if (s->drp) s->drp = (s32*)(int)(s->drp - scsp_decay_rate); if (s->srp == &scsp_null_rate[0]) s->srp = (s32*)(void*)0xdeadbeef; - else + else if (s->srp) s->srp = (s32*)(int)(s->srp - scsp_decay_rate); if (s->rrp == &scsp_null_rate[0]) s->rrp = (s32*)(void*)0xdeadbeef; - else + else if (s->rrp) s->rrp = (s32*)(int)(s->rrp - scsp_decay_rate); if (s->lfofmw == scsp_lfo_sawt_f) @@ -3808,25 +3812,27 @@ void StateFlatten(slot_t *s) void StateUnFlatten(slot_t *s) { - s->buf8 = (s8*)scsp.scsp_ram + (int)(s->buf8); - s->buf16 = (s16*)scsp.scsp_ram + (int)(s->buf16); + if (s->buf8) + s->buf8 = (s8*)scsp.scsp_ram + (int)(s->buf8); + if (s->buf16) + s->buf16 = (s16*)scsp.scsp_ram + (int)(s->buf16); if (s->einc) s->einc = (s32*)s + (int)(s->einc); if (s->arp == (void*)0xdeadbeef) s->arp = &scsp_null_rate[0]; - else + else if (s->arp) s->arp = scsp_attack_rate + (int)(s->arp); if (s->drp == (void*)0xdeadbeef) s->drp = &scsp_null_rate[0]; - else + else if (s->drp) s->drp = scsp_decay_rate + (int)(s->drp); if (s->srp == (void*)0xdeadbeef) s->srp = &scsp_null_rate[0]; - else + else if (s->srp) s->srp = scsp_decay_rate + (int)(s->srp); if (s->rrp == (void*)0xdeadbeef) s->rrp = &scsp_null_rate[0]; - else + else if (s->rrp) s->rrp = scsp_decay_rate + (int)(s->rrp); switch ((int)(s->lfofmw)) diff --git a/yabause/src/smpc.c b/yabause/src/smpc.c index 80c4b77e52..30fd64b7c4 100644 --- a/yabause/src/smpc.c +++ b/yabause/src/smpc.c @@ -1,812 +1,812 @@ -/* Copyright 2003-2005 Guillaume Duhamel - Copyright 2004-2006 Theo Berkau - - This file is part of Yabause. - - Yabause 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. - - Yabause 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 Yabause; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include "smpc.h" -#include "cs2.h" -#include "debug.h" -#include "peripheral.h" -#include "scsp.h" -#include "scu.h" -#include "sh2core.h" -#include "vdp1.h" -#include "vdp2.h" -#include "yabause.h" -#include "movie.h" - -#ifdef _arch_dreamcast -# include "dreamcast/localtime.h" -#endif -#ifdef PSP -# include "psp/localtime.h" -#endif - -Smpc * SmpcRegs; -u8 * SmpcRegsT; -SmpcInternal * SmpcInternalVars; - -////////////////////////////////////////////////////////////////////////////// - -int SmpcInit(u8 regionid, int clocksync, u32 basetime) { - if ((SmpcRegsT = (u8 *) calloc(1, sizeof(Smpc))) == NULL) - return -1; - - SmpcRegs = (Smpc *) SmpcRegsT; - - if ((SmpcInternalVars = (SmpcInternal *) calloc(1, sizeof(SmpcInternal))) == NULL) - return -1; - - SmpcInternalVars->regionsetting = regionid; - SmpcInternalVars->regionid = regionid; - SmpcInternalVars->clocksync = clocksync; - SmpcInternalVars->basetime = basetime ? basetime : time(NULL); - - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcDeInit(void) { - if (SmpcRegsT) - free(SmpcRegsT); - SmpcRegsT = NULL; - - if (SmpcInternalVars) - free(SmpcInternalVars); - SmpcInternalVars = NULL; -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcRecheckRegion(void) { - if (SmpcInternalVars == NULL) - return; - - if (SmpcInternalVars->regionsetting == REGION_AUTODETECT) - { - // Time to autodetect the region using the cd block - SmpcInternalVars->regionid = Cs2GetRegionID(); - - // Since we couldn't detect the region from the CD, let's assume - // it's japanese - if (SmpcInternalVars->regionid == 0) - SmpcInternalVars->regionid = 1; - } - else - Cs2GetIP(0); -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcReset(void) { - memset((void *)SmpcRegs, 0, sizeof(Smpc)); - memset((void *)SmpcInternalVars->SMEM, 0, 4); - - SmpcRecheckRegion(); - - SmpcInternalVars->dotsel = 0; - SmpcInternalVars->mshnmi = 0; - SmpcInternalVars->sysres = 0; - SmpcInternalVars->sndres = 0; - SmpcInternalVars->cdres = 0; - SmpcInternalVars->resd = 1; - SmpcInternalVars->ste = 0; - SmpcInternalVars->resb = 0; - - SmpcInternalVars->intback=0; - SmpcInternalVars->intbackIreg0=0; - SmpcInternalVars->firstPeri=0; - - SmpcInternalVars->timing=0; - - memset((void *)&SmpcInternalVars->port1, 0, sizeof(PortData_struct)); - memset((void *)&SmpcInternalVars->port2, 0, sizeof(PortData_struct)); -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSSHON(void) { - YabauseStartSlave(); -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSSHOFF(void) { - YabauseStopSlave(); -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSNDON(void) { - M68KStart(); - SmpcRegs->OREG[31] = 0x6; -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSNDOFF(void) { - M68KStop(); - SmpcRegs->OREG[31] = 0x7; -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcCKCHG352(void) { - // Reset VDP1, VDP2, SCU, and SCSP - Vdp1Reset(); - Vdp2Reset(); - ScuReset(); - ScspReset(); - - // Clear VDP1/VDP2 ram - - YabauseStopSlave(); - - // change clock - YabauseChangeTiming(CLKTYPE_28MHZ); - - // Set DOTSEL - SmpcInternalVars->dotsel = 1; - - // Send NMI - SH2NMI(MSH2); -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcCKCHG320(void) { - // Reset VDP1, VDP2, SCU, and SCSP - Vdp1Reset(); - Vdp2Reset(); - ScuReset(); - ScspReset(); - - // Clear VDP1/VDP2 ram - - YabauseStopSlave(); - - // change clock - YabauseChangeTiming(CLKTYPE_26MHZ); - - // Set DOTSEL - SmpcInternalVars->dotsel = 0; - - // Send NMI - SH2NMI(MSH2); -} - -struct movietime { - - int tm_year; - int tm_wday; - int tm_mon; - int tm_mday; - int tm_hour; - int tm_min; - int tm_sec; -}; - -static struct movietime movietime; -int totalseconds; -int noon= 43200; - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcINTBACKStatus(void) { - // return time, cartidge, zone, etc. data - int i; - struct tm times; - u8 year[4]; - time_t tmp; - - SmpcRegs->OREG[0] = 0x80 | (SmpcInternalVars->resd << 6); // goto normal startup - //SmpcRegs->OREG[0] = 0x0 | (SmpcInternalVars->resd << 6); // goto setclock/setlanguage screen - - // write time data in OREG1-7 - if (SmpcInternalVars->clocksync) { - tmp = SmpcInternalVars->basetime + ((u64)framecounter * 1001 / 60000); - } else { - tmp = time(NULL); - } -#ifdef WIN32 - memcpy(×, localtime(&tmp), sizeof(times)); -#elif defined(_arch_dreamcast) || defined(PSP) - internal_localtime_r(&tmp, ×); -#else - localtime_r(&tmp, ×); -#endif - year[0] = (1900 + times.tm_year) / 1000; - year[1] = ((1900 + times.tm_year) % 1000) / 100; - year[2] = (((1900 + times.tm_year) % 1000) % 100) / 10; - year[3] = (((1900 + times.tm_year) % 1000) % 100) % 10; - SmpcRegs->OREG[1] = (year[0] << 4) | year[1]; - SmpcRegs->OREG[2] = (year[2] << 4) | year[3]; - SmpcRegs->OREG[3] = (times.tm_wday << 4) | (times.tm_mon + 1); - SmpcRegs->OREG[4] = ((times.tm_mday / 10) << 4) | (times.tm_mday % 10); - SmpcRegs->OREG[5] = ((times.tm_hour / 10) << 4) | (times.tm_hour % 10); - SmpcRegs->OREG[6] = ((times.tm_min / 10) << 4) | (times.tm_min % 10); - SmpcRegs->OREG[7] = ((times.tm_sec / 10) << 4) | (times.tm_sec % 10); - - if(Movie.Status == Recording || Movie.Status == Playback) { - movietime.tm_year=0x62; - movietime.tm_wday=0x04; - movietime.tm_mday=0x01; - movietime.tm_mon=0; - totalseconds = ((framecounter / 60) + noon); - - movietime.tm_sec=totalseconds % 60; - movietime.tm_min=totalseconds/60; - movietime.tm_hour=movietime.tm_min/60; - - //convert to sane numbers - movietime.tm_min=movietime.tm_min % 60; - movietime.tm_hour=movietime.tm_hour % 24; - - year[0] = (1900 + movietime.tm_year) / 1000; - year[1] = ((1900 + movietime.tm_year) % 1000) / 100; - year[2] = (((1900 + movietime.tm_year) % 1000) % 100) / 10; - year[3] = (((1900 + movietime.tm_year) % 1000) % 100) % 10; - SmpcRegs->OREG[1] = (year[0] << 4) | year[1]; - SmpcRegs->OREG[2] = (year[2] << 4) | year[3]; - SmpcRegs->OREG[3] = (movietime.tm_wday << 4) | (movietime.tm_mon + 1); - SmpcRegs->OREG[4] = ((movietime.tm_mday / 10) << 4) | (movietime.tm_mday % 10); - SmpcRegs->OREG[5] = ((movietime.tm_hour / 10) << 4) | (movietime.tm_hour % 10); - SmpcRegs->OREG[6] = ((movietime.tm_min / 10) << 4) | (movietime.tm_min % 10); - SmpcRegs->OREG[7] = ((movietime.tm_sec / 10) << 4) | (movietime.tm_sec % 10); - } - - // write cartidge data in OREG8 - SmpcRegs->OREG[8] = 0; // FIXME : random value - - // write zone data in OREG9 bits 0-7 - // 1 -> japan - // 2 -> asia/ntsc - // 4 -> north america - // 5 -> central/south america/ntsc - // 6 -> corea - // A -> asia/pal - // C -> europe + others/pal - // D -> central/south america/pal - SmpcRegs->OREG[9] = SmpcInternalVars->regionid; - - // system state, first part in OREG10, bits 0-7 - // bit | value | comment - // --------------------------- - // 7 | 0 | - // 6 | DOTSEL | - // 5 | 1 | - // 4 | 1 | - // 3 | MSHNMI | - // 2 | 1 | - // 1 | SYSRES | - // 0 | SNDRES | - SmpcRegs->OREG[10] = 0x34|(SmpcInternalVars->dotsel<<6)|(SmpcInternalVars->mshnmi<<3)|(SmpcInternalVars->sysres<<1)|SmpcInternalVars->sndres; - - // system state, second part in OREG11, bit 6 - // bit 6 -> CDRES - SmpcRegs->OREG[11] = SmpcInternalVars->cdres << 6; // FIXME - - // SMEM - for(i = 0;i < 4;i++) - SmpcRegs->OREG[12+i] = SmpcInternalVars->SMEM[i]; - - SmpcRegs->OREG[31] = 0x10; // set to intback command -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcINTBACKPeripheral(void) { - int oregoffset; - PortData_struct *port1, *port2; - - if (SmpcInternalVars->firstPeri) - SmpcRegs->SR = 0xC0 | (SmpcRegs->IREG[1] >> 4); - else - SmpcRegs->SR = 0x80 | (SmpcRegs->IREG[1] >> 4); - - SmpcInternalVars->firstPeri = 0; - - /* Port Status: - 0x04 - Sega-tap is connected - 0x16 - Multi-tap is connected - 0x21-0x2F - Clock serial peripheral is connected - 0xF0 - Not Connected or Unknown Device - 0xF1 - Peripheral is directly connected */ - - /* PeripheralID: - 0x02 - Digital Device Standard Format - 0x13 - Racing Device Standard Format - 0x15 - Analog Device Standard Format - 0x23 - Pointing Device Standard Format - 0x23 - Shooting Device Standard Format - 0x34 - Keyboard Device Standard Format - 0xE1 - Mega Drive 3-Button Pad - 0xE2 - Mega Drive 6-Button Pad - 0xE3 - Saturn Mouse - 0xFF - Not Connected */ - - /* Special Notes(for potential future uses): - - If a peripheral is disconnected from a port, you only return 1 byte for - that port(which is the port status 0xF0), at the next OREG you then return - the port status of the next port. - - e.g. If Port 1 has nothing connected, and Port 2 has a controller - connected: - - OREG0 = 0xF0 - OREG1 = 0xF1 - OREG2 = 0x02 - etc. - */ - - oregoffset=0; - - if (SmpcInternalVars->port1.size == 0 && SmpcInternalVars->port2.size == 0) - { - // Request data from the Peripheral Interface - port1 = &PORTDATA1; - port2 = &PORTDATA2; - memcpy(&SmpcInternalVars->port1, port1, sizeof(PortData_struct)); - memcpy(&SmpcInternalVars->port2, port2, sizeof(PortData_struct)); - PerFlush(&PORTDATA1); - PerFlush(&PORTDATA2); - SmpcInternalVars->port1.offset = 0; - SmpcInternalVars->port2.offset = 0; - LagFrameFlag=0; - } - - // Port 1 - if (SmpcInternalVars->port1.size > 0) - { - if ((SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset) < 32) - { - memcpy(SmpcRegs->OREG, SmpcInternalVars->port1.data+SmpcInternalVars->port1.offset, SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset); - oregoffset += SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset; - SmpcInternalVars->port1.size = 0; - } - else - { - memcpy(SmpcRegs->OREG, SmpcInternalVars->port1.data, 32); - oregoffset += 32; - SmpcInternalVars->port1.offset += 32; - } - } - // Port 2 - if (SmpcInternalVars->port2.size > 0 && oregoffset < 32) - { - if ((SmpcInternalVars->port2.size-SmpcInternalVars->port2.offset) < (32 - oregoffset)) - { - memcpy(SmpcRegs->OREG + oregoffset, SmpcInternalVars->port2.data+SmpcInternalVars->port2.offset, SmpcInternalVars->port2.size-SmpcInternalVars->port2.offset); - SmpcInternalVars->port2.size = 0; - } - else - { - memcpy(SmpcRegs->OREG + oregoffset, SmpcInternalVars->port2.data, 32 - oregoffset); - SmpcInternalVars->port2.offset += 32 - oregoffset; - } - } - -/* - Use this as a reference for implementing other peripherals - // Port 1 - SmpcRegs->OREG[0] = 0xF1; //Port Status(Directly Connected) - SmpcRegs->OREG[1] = 0xE3; //PeripheralID(Shuttle Mouse) - SmpcRegs->OREG[2] = 0x00; //First Data - SmpcRegs->OREG[3] = 0x00; //Second Data - SmpcRegs->OREG[4] = 0x00; //Third Data - - // Port 2 - SmpcRegs->OREG[5] = 0xF0; //Port Status(Not Connected) -*/ -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcINTBACK(void) { - SmpcRegs->SF = 1; - - if (SmpcInternalVars->intback) { - SmpcINTBACKPeripheral(); - ScuSendSystemManager(); - return; - } +/* Copyright 2003-2005 Guillaume Duhamel + Copyright 2004-2006 Theo Berkau + + This file is part of Yabause. + + Yabause 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. + + Yabause 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 Yabause; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "smpc.h" +#include "cs2.h" +#include "debug.h" +#include "peripheral.h" +#include "scsp.h" +#include "scu.h" +#include "sh2core.h" +#include "vdp1.h" +#include "vdp2.h" +#include "yabause.h" +#include "movie.h" + +#ifdef _arch_dreamcast +# include "dreamcast/localtime.h" +#endif +#ifdef PSP +# include "psp/localtime.h" +#endif + +Smpc * SmpcRegs; +u8 * SmpcRegsT; +SmpcInternal * SmpcInternalVars; + +////////////////////////////////////////////////////////////////////////////// + +int SmpcInit(u8 regionid, int clocksync, u32 basetime) { + if ((SmpcRegsT = (u8 *) calloc(1, sizeof(Smpc))) == NULL) + return -1; + + SmpcRegs = (Smpc *) SmpcRegsT; + + if ((SmpcInternalVars = (SmpcInternal *) calloc(1, sizeof(SmpcInternal))) == NULL) + return -1; + + SmpcInternalVars->regionsetting = regionid; + SmpcInternalVars->regionid = regionid; + SmpcInternalVars->clocksync = clocksync; + SmpcInternalVars->basetime = basetime ? basetime : time(NULL); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcDeInit(void) { + if (SmpcRegsT) + free(SmpcRegsT); + SmpcRegsT = NULL; + + if (SmpcInternalVars) + free(SmpcInternalVars); + SmpcInternalVars = NULL; +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcRecheckRegion(void) { + if (SmpcInternalVars == NULL) + return; + + if (SmpcInternalVars->regionsetting == REGION_AUTODETECT) + { + // Time to autodetect the region using the cd block + SmpcInternalVars->regionid = Cs2GetRegionID(); + + // Since we couldn't detect the region from the CD, let's assume + // it's japanese + if (SmpcInternalVars->regionid == 0) + SmpcInternalVars->regionid = 1; + } + else + Cs2GetIP(0); +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcReset(void) { + memset((void *)SmpcRegs, 0, sizeof(Smpc)); + memset((void *)SmpcInternalVars->SMEM, 0, 4); + + SmpcRecheckRegion(); + + SmpcInternalVars->dotsel = 0; + SmpcInternalVars->mshnmi = 0; + SmpcInternalVars->sysres = 0; + SmpcInternalVars->sndres = 0; + SmpcInternalVars->cdres = 0; + SmpcInternalVars->resd = 1; + SmpcInternalVars->ste = 0; + SmpcInternalVars->resb = 0; + + SmpcInternalVars->intback=0; + SmpcInternalVars->intbackIreg0=0; + SmpcInternalVars->firstPeri=0; + + SmpcInternalVars->timing=0; + + memset((void *)&SmpcInternalVars->port1, 0, sizeof(PortData_struct)); + memset((void *)&SmpcInternalVars->port2, 0, sizeof(PortData_struct)); +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSSHON(void) { + YabauseStartSlave(); +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSSHOFF(void) { + YabauseStopSlave(); +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSNDON(void) { + M68KStart(); + SmpcRegs->OREG[31] = 0x6; +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSNDOFF(void) { + M68KStop(); + SmpcRegs->OREG[31] = 0x7; +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcCKCHG352(void) { + // Reset VDP1, VDP2, SCU, and SCSP + Vdp1Reset(); + Vdp2Reset(); + ScuReset(); + ScspReset(); + + // Clear VDP1/VDP2 ram + + YabauseStopSlave(); + + // change clock + YabauseChangeTiming(CLKTYPE_28MHZ); + + // Set DOTSEL + SmpcInternalVars->dotsel = 1; + + // Send NMI + SH2NMI(MSH2); +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcCKCHG320(void) { + // Reset VDP1, VDP2, SCU, and SCSP + Vdp1Reset(); + Vdp2Reset(); + ScuReset(); + ScspReset(); + + // Clear VDP1/VDP2 ram + + YabauseStopSlave(); + + // change clock + YabauseChangeTiming(CLKTYPE_26MHZ); + + // Set DOTSEL + SmpcInternalVars->dotsel = 0; + + // Send NMI + SH2NMI(MSH2); +} + +struct movietime { + + int tm_year; + int tm_wday; + int tm_mon; + int tm_mday; + int tm_hour; + int tm_min; + int tm_sec; +}; + +static struct movietime movietime; +int totalseconds; +int noon= 43200; + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcINTBACKStatus(void) { + // return time, cartidge, zone, etc. data + int i; + struct tm times; + u8 year[4]; + time_t tmp; + + SmpcRegs->OREG[0] = 0x80 | (SmpcInternalVars->resd << 6); // goto normal startup + //SmpcRegs->OREG[0] = 0x0 | (SmpcInternalVars->resd << 6); // goto setclock/setlanguage screen + + // write time data in OREG1-7 + if (SmpcInternalVars->clocksync) { + tmp = SmpcInternalVars->basetime + ((u64)framecounter * 1001 / 60000); + } else { + tmp = time(NULL); + } +#ifdef WIN32 + memcpy(×, localtime(&tmp), sizeof(times)); +#elif defined(_arch_dreamcast) || defined(PSP) + internal_localtime_r(&tmp, ×); +#else + localtime_r(&tmp, ×); +#endif + year[0] = (1900 + times.tm_year) / 1000; + year[1] = ((1900 + times.tm_year) % 1000) / 100; + year[2] = (((1900 + times.tm_year) % 1000) % 100) / 10; + year[3] = (((1900 + times.tm_year) % 1000) % 100) % 10; + SmpcRegs->OREG[1] = (year[0] << 4) | year[1]; + SmpcRegs->OREG[2] = (year[2] << 4) | year[3]; + SmpcRegs->OREG[3] = (times.tm_wday << 4) | (times.tm_mon + 1); + SmpcRegs->OREG[4] = ((times.tm_mday / 10) << 4) | (times.tm_mday % 10); + SmpcRegs->OREG[5] = ((times.tm_hour / 10) << 4) | (times.tm_hour % 10); + SmpcRegs->OREG[6] = ((times.tm_min / 10) << 4) | (times.tm_min % 10); + SmpcRegs->OREG[7] = ((times.tm_sec / 10) << 4) | (times.tm_sec % 10); + + if(Movie.Status == Recording || Movie.Status == Playback) { + movietime.tm_year=0x62; + movietime.tm_wday=0x04; + movietime.tm_mday=0x01; + movietime.tm_mon=0; + totalseconds = ((framecounter / 60) + noon); + + movietime.tm_sec=totalseconds % 60; + movietime.tm_min=totalseconds/60; + movietime.tm_hour=movietime.tm_min/60; + + //convert to sane numbers + movietime.tm_min=movietime.tm_min % 60; + movietime.tm_hour=movietime.tm_hour % 24; + + year[0] = (1900 + movietime.tm_year) / 1000; + year[1] = ((1900 + movietime.tm_year) % 1000) / 100; + year[2] = (((1900 + movietime.tm_year) % 1000) % 100) / 10; + year[3] = (((1900 + movietime.tm_year) % 1000) % 100) % 10; + SmpcRegs->OREG[1] = (year[0] << 4) | year[1]; + SmpcRegs->OREG[2] = (year[2] << 4) | year[3]; + SmpcRegs->OREG[3] = (movietime.tm_wday << 4) | (movietime.tm_mon + 1); + SmpcRegs->OREG[4] = ((movietime.tm_mday / 10) << 4) | (movietime.tm_mday % 10); + SmpcRegs->OREG[5] = ((movietime.tm_hour / 10) << 4) | (movietime.tm_hour % 10); + SmpcRegs->OREG[6] = ((movietime.tm_min / 10) << 4) | (movietime.tm_min % 10); + SmpcRegs->OREG[7] = ((movietime.tm_sec / 10) << 4) | (movietime.tm_sec % 10); + } + + // write cartidge data in OREG8 + SmpcRegs->OREG[8] = 0; // FIXME : random value + + // write zone data in OREG9 bits 0-7 + // 1 -> japan + // 2 -> asia/ntsc + // 4 -> north america + // 5 -> central/south america/ntsc + // 6 -> corea + // A -> asia/pal + // C -> europe + others/pal + // D -> central/south america/pal + SmpcRegs->OREG[9] = SmpcInternalVars->regionid; + + // system state, first part in OREG10, bits 0-7 + // bit | value | comment + // --------------------------- + // 7 | 0 | + // 6 | DOTSEL | + // 5 | 1 | + // 4 | 1 | + // 3 | MSHNMI | + // 2 | 1 | + // 1 | SYSRES | + // 0 | SNDRES | + SmpcRegs->OREG[10] = 0x34|(SmpcInternalVars->dotsel<<6)|(SmpcInternalVars->mshnmi<<3)|(SmpcInternalVars->sysres<<1)|SmpcInternalVars->sndres; + + // system state, second part in OREG11, bit 6 + // bit 6 -> CDRES + SmpcRegs->OREG[11] = SmpcInternalVars->cdres << 6; // FIXME + + // SMEM + for(i = 0;i < 4;i++) + SmpcRegs->OREG[12+i] = SmpcInternalVars->SMEM[i]; + + SmpcRegs->OREG[31] = 0x10; // set to intback command +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcINTBACKPeripheral(void) { + int oregoffset; + PortData_struct *port1, *port2; + + if (SmpcInternalVars->firstPeri) + SmpcRegs->SR = 0xC0 | (SmpcRegs->IREG[1] >> 4); + else + SmpcRegs->SR = 0x80 | (SmpcRegs->IREG[1] >> 4); + + SmpcInternalVars->firstPeri = 0; + + /* Port Status: + 0x04 - Sega-tap is connected + 0x16 - Multi-tap is connected + 0x21-0x2F - Clock serial peripheral is connected + 0xF0 - Not Connected or Unknown Device + 0xF1 - Peripheral is directly connected */ + + /* PeripheralID: + 0x02 - Digital Device Standard Format + 0x13 - Racing Device Standard Format + 0x15 - Analog Device Standard Format + 0x23 - Pointing Device Standard Format + 0x23 - Shooting Device Standard Format + 0x34 - Keyboard Device Standard Format + 0xE1 - Mega Drive 3-Button Pad + 0xE2 - Mega Drive 6-Button Pad + 0xE3 - Saturn Mouse + 0xFF - Not Connected */ + + /* Special Notes(for potential future uses): + + If a peripheral is disconnected from a port, you only return 1 byte for + that port(which is the port status 0xF0), at the next OREG you then return + the port status of the next port. + + e.g. If Port 1 has nothing connected, and Port 2 has a controller + connected: + + OREG0 = 0xF0 + OREG1 = 0xF1 + OREG2 = 0x02 + etc. + */ + + oregoffset=0; + + if (SmpcInternalVars->port1.size == 0 && SmpcInternalVars->port2.size == 0) + { + // Request data from the Peripheral Interface + port1 = &PORTDATA1; + port2 = &PORTDATA2; + memcpy(&SmpcInternalVars->port1, port1, sizeof(PortData_struct)); + memcpy(&SmpcInternalVars->port2, port2, sizeof(PortData_struct)); + PerFlush(&PORTDATA1); + PerFlush(&PORTDATA2); + SmpcInternalVars->port1.offset = 0; + SmpcInternalVars->port2.offset = 0; + LagFrameFlag=0; + } + + // Port 1 + if (SmpcInternalVars->port1.size > 0) + { + if ((SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset) < 32) + { + memcpy(SmpcRegs->OREG, SmpcInternalVars->port1.data+SmpcInternalVars->port1.offset, SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset); + oregoffset += SmpcInternalVars->port1.size-SmpcInternalVars->port1.offset; + SmpcInternalVars->port1.size = 0; + } + else + { + memcpy(SmpcRegs->OREG, SmpcInternalVars->port1.data, 32); + oregoffset += 32; + SmpcInternalVars->port1.offset += 32; + } + } + // Port 2 + if (SmpcInternalVars->port2.size > 0 && oregoffset < 32) + { + if ((SmpcInternalVars->port2.size-SmpcInternalVars->port2.offset) < (32 - oregoffset)) + { + memcpy(SmpcRegs->OREG + oregoffset, SmpcInternalVars->port2.data+SmpcInternalVars->port2.offset, SmpcInternalVars->port2.size-SmpcInternalVars->port2.offset); + SmpcInternalVars->port2.size = 0; + } + else + { + memcpy(SmpcRegs->OREG + oregoffset, SmpcInternalVars->port2.data, 32 - oregoffset); + SmpcInternalVars->port2.offset += 32 - oregoffset; + } + } + +/* + Use this as a reference for implementing other peripherals + // Port 1 + SmpcRegs->OREG[0] = 0xF1; //Port Status(Directly Connected) + SmpcRegs->OREG[1] = 0xE3; //PeripheralID(Shuttle Mouse) + SmpcRegs->OREG[2] = 0x00; //First Data + SmpcRegs->OREG[3] = 0x00; //Second Data + SmpcRegs->OREG[4] = 0x00; //Third Data + + // Port 2 + SmpcRegs->OREG[5] = 0xF0; //Port Status(Not Connected) +*/ +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcINTBACK(void) { + SmpcRegs->SF = 1; + + if (SmpcInternalVars->intback) { + SmpcINTBACKPeripheral(); + ScuSendSystemManager(); + return; + } //we think rayman sets 0x40 so that it breaks the intback command immediately when it blocks, //rather than having to set 0x40 in response to an interrupt if ((SmpcInternalVars->intbackIreg0 = (SmpcRegs->IREG[0] & 1))) { - // Return non-peripheral data - SmpcInternalVars->firstPeri = 1; - SmpcInternalVars->intback = (SmpcRegs->IREG[1] & 0x8) >> 3; // does the program want peripheral data too? - SmpcINTBACKStatus(); - SmpcRegs->SR = 0x4F | (SmpcInternalVars->intback << 5); // the low nibble is undefined(or 0xF) - ScuSendSystemManager(); - return; - } - if (SmpcRegs->IREG[1] & 0x8) { - SmpcInternalVars->firstPeri = 1; - SmpcInternalVars->intback = 1; - SmpcRegs->SR = 0x40; - SmpcINTBACKPeripheral(); - SmpcRegs->OREG[31] = 0x10; // may need to be changed - ScuSendSystemManager(); - return; - } -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcINTBACKEnd(void) { - SmpcInternalVars->intback = 0; -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSETSMEM(void) { - int i; - - for(i = 0;i < 4;i++) - SmpcInternalVars->SMEM[i] = SmpcRegs->IREG[i]; - - SmpcRegs->OREG[31] = 0x17; -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcNMIREQ(void) { - SH2SendInterrupt(MSH2, 0xB, 16); - SmpcRegs->OREG[31] = 0x18; -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcResetButton(void) { - // If RESD isn't set, send an NMI request to the MSH2. - if (SmpcInternalVars->resd) - return; - - SH2SendInterrupt(MSH2, 0xB, 16); -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcRESENAB(void) { - SmpcInternalVars->resd = 0; - SmpcRegs->OREG[31] = 0x19; -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcRESDISA(void) { - SmpcInternalVars->resd = 1; - SmpcRegs->OREG[31] = 0x1A; -} - -////////////////////////////////////////////////////////////////////////////// - -void SmpcExec(s32 t) { - if (SmpcInternalVars->timing > 0) { - SmpcInternalVars->timing -= t; - if (SmpcInternalVars->timing <= 0) { - switch(SmpcRegs->COMREG) { - case 0x0: - SMPCLOG("smpc\t: MSHON not implemented\n"); - break; - case 0x2: - SMPCLOG("smpc\t: SSHON\n"); - SmpcSSHON(); - break; - case 0x3: - SMPCLOG("smpc\t: SSHOFF\n"); - SmpcSSHOFF(); - break; - case 0x6: - SMPCLOG("smpc\t: SNDON\n"); - SmpcSNDON(); - break; - case 0x7: - SMPCLOG("smpc\t: SNDOFF\n"); - SmpcSNDOFF(); - break; - case 0x8: - SMPCLOG("smpc\t: CDON not implemented\n"); - break; - case 0x9: - SMPCLOG("smpc\t: CDOFF not implemented\n"); - break; - case 0xD: - SMPCLOG("smpc\t: SYSRES not implemented\n"); - break; - case 0xE: - SMPCLOG("smpc\t: CKCHG352\n"); - SmpcCKCHG352(); - break; - case 0xF: - SMPCLOG("smpc\t: CKCHG320\n"); - SmpcCKCHG320(); - break; - case 0x10: - SMPCLOG("smpc\t: INTBACK\n"); - SmpcINTBACK(); - break; - case 0x17: - SMPCLOG("smpc\t: SETSMEM\n"); - SmpcSETSMEM(); - break; - case 0x18: - SMPCLOG("smpc\t: NMIREQ\n"); - SmpcNMIREQ(); - break; - case 0x19: - SMPCLOG("smpc\t: RESENAB\n"); - SmpcRESENAB(); - break; - case 0x1A: - SMPCLOG("smpc\t: RESDISA\n"); - SmpcRESDISA(); - break; - default: - SMPCLOG("smpc\t: Command %02X not implemented\n", SmpcRegs->COMREG); - break; - } - - SmpcRegs->SF = 0; - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -u8 FASTCALL SmpcReadByte(u32 addr) { - addr &= 0x7F; - - return SmpcRegsT[addr >> 1]; -} - -////////////////////////////////////////////////////////////////////////////// - -u16 FASTCALL SmpcReadWord(USED_IF_SMPC_DEBUG u32 addr) { - // byte access only - SMPCLOG("smpc\t: SMPC register read word - %08X\n", addr); - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - -u32 FASTCALL SmpcReadLong(USED_IF_SMPC_DEBUG u32 addr) { - // byte access only - SMPCLOG("smpc\t: SMPC register read long - %08X\n", addr); - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - -static void SmpcSetTiming(void) { - switch(SmpcRegs->COMREG) { - case 0x0: - SMPCLOG("smpc\t: MSHON not implemented\n"); - SmpcInternalVars->timing = 1; - return; - case 0x8: - SMPCLOG("smpc\t: CDON not implemented\n"); - SmpcInternalVars->timing = 1; - return; - case 0x9: - SMPCLOG("smpc\t: CDOFF not implemented\n"); - SmpcInternalVars->timing = 1; - return; - case 0xD: - case 0xE: - case 0xF: - SmpcInternalVars->timing = 1; // this has to be tested on a real saturn - return; - case 0x10: - if (SmpcInternalVars->intback) - SmpcInternalVars->timing = 20; // this will need to be verified - else { - // Calculate timing based on what data is being retrieved - - SmpcInternalVars->timing = 1; - - // If retrieving non-peripheral data, add 0.2 milliseconds - if (SmpcRegs->IREG[0] == 0x01) - SmpcInternalVars->timing += 2; - - // If retrieving peripheral data, add 15 milliseconds - if (SmpcRegs->IREG[1] & 0x8) - SmpcInternalVars->timing += 16000; // Strangely enough, this works better -// SmpcInternalVars->timing += 150; - } - return; - case 0x17: - SmpcInternalVars->timing = 1; - return; - case 0x2: - SmpcInternalVars->timing = 1; - return; - case 0x3: - SmpcInternalVars->timing = 1; - return; - case 0x6: - case 0x7: - case 0x18: - case 0x19: - case 0x1A: - SmpcInternalVars->timing = 1; - return; - default: - SMPCLOG("smpc\t: unimplemented command: %02X\n", SmpcRegs->COMREG); - SmpcRegs->SF = 0; - break; - } -} - -////////////////////////////////////////////////////////////////////////////// - -void FASTCALL SmpcWriteByte(u32 addr, u8 val) { - addr &= 0x7F; - SmpcRegsT[addr >> 1] = val; - - switch(addr) { - case 0x01: // Maybe an INTBACK continue/break request - if (SmpcInternalVars->intback) - { - if (SmpcRegs->IREG[0] & 0x40) { - // Break - SmpcInternalVars->intback = 0; - SmpcRegs->SR &= 0x0F; - break; - } - else if (SmpcRegs->IREG[0] & 0x80) { - // Continue - SmpcRegs->COMREG = 0x10; - SmpcSetTiming(); - SmpcRegs->SF = 1; - } - } - return; - case 0x1F: - SmpcSetTiming(); - return; - case 0x63: - SmpcRegs->SF &= 0x1; - return; - case 0x75: - // FIX ME (should support other peripherals) - - switch (SmpcRegs->DDR[0] & 0x7F) { // Which Control Method do we use? - case 0x40: - SMPCLOG("smpc\t: Peripheral TH Control Method not implemented\n"); - break; - case 0x60: - switch (val & 0x60) { - case 0x60: // 1st Data - val = (val & 0x80) | 0x14 | (PORTDATA1.data[1] & 0x8); - break; - case 0x20: // 2nd Data - val = (val & 0x80) | 0x10 | ((PORTDATA1.data[2] >> 4) & 0xF); - break; - case 0x40: // 3rd Data - val = (val & 0x80) | 0x10 | (PORTDATA1.data[2] & 0xF); - break; - case 0x00: // 4th Data - val = (val & 0x80) | 0x10 | ((PORTDATA1.data[1] >> 4) & 0xF); - break; - default: break; - } - - SmpcRegs->PDR[0] = val; - break; - default: - SMPCLOG("smpc\t: Peripheral Unknown Control Method not implemented\n"); - break; - } - - return; - default: - return; - } -} - -////////////////////////////////////////////////////////////////////////////// - -void FASTCALL SmpcWriteWord(USED_IF_SMPC_DEBUG u32 addr, UNUSED u16 val) { - // byte access only - SMPCLOG("smpc\t: SMPC register write word - %08X\n", addr); -} - -////////////////////////////////////////////////////////////////////////////// - -void FASTCALL SmpcWriteLong(USED_IF_SMPC_DEBUG u32 addr, UNUSED u32 val) { - // byte access only - SMPCLOG("smpc\t: SMPC register write long - %08X\n", addr); -} - -////////////////////////////////////////////////////////////////////////////// - -int SmpcSaveState(FILE *fp) -{ - int offset; - IOCheck_struct check; - - offset = StateWriteHeader(fp, "SMPC", 3); - - // Write registers - ywrite(&check, (void *)SmpcRegs->IREG, sizeof(u8), 7, fp); - ywrite(&check, (void *)&SmpcRegs->COMREG, sizeof(u8), 1, fp); - ywrite(&check, (void *)SmpcRegs->OREG, sizeof(u8), 32, fp); - ywrite(&check, (void *)&SmpcRegs->SR, sizeof(u8), 1, fp); - ywrite(&check, (void *)&SmpcRegs->SF, sizeof(u8), 1, fp); - ywrite(&check, (void *)SmpcRegs->PDR, sizeof(u8), 2, fp); - ywrite(&check, (void *)SmpcRegs->DDR, sizeof(u8), 2, fp); - ywrite(&check, (void *)&SmpcRegs->IOSEL, sizeof(u8), 1, fp); - ywrite(&check, (void *)&SmpcRegs->EXLE, sizeof(u8), 1, fp); - - // Write internal variables - ywrite(&check, (void *)SmpcInternalVars, sizeof(SmpcInternal), 1, fp); - - // Write ID's of currently emulated peripherals(fix me) - - return StateFinishHeader(fp, offset); -} - -////////////////////////////////////////////////////////////////////////////// - -int SmpcLoadState(FILE *fp, int version, int size) -{ - IOCheck_struct check; - int internalsizev2 = sizeof(SmpcInternal) - 8; - - // Read registers - yread(&check, (void *)SmpcRegs->IREG, sizeof(u8), 7, fp); - yread(&check, (void *)&SmpcRegs->COMREG, sizeof(u8), 1, fp); - yread(&check, (void *)SmpcRegs->OREG, sizeof(u8), 32, fp); - yread(&check, (void *)&SmpcRegs->SR, sizeof(u8), 1, fp); - yread(&check, (void *)&SmpcRegs->SF, sizeof(u8), 1, fp); - yread(&check, (void *)SmpcRegs->PDR, sizeof(u8), 2, fp); - yread(&check, (void *)SmpcRegs->DDR, sizeof(u8), 2, fp); - yread(&check, (void *)&SmpcRegs->IOSEL, sizeof(u8), 1, fp); - yread(&check, (void *)&SmpcRegs->EXLE, sizeof(u8), 1, fp); - - // Read internal variables - if (version == 1) - { - // This handles the problem caused by the version not being incremented - // when SmpcInternal was changed - if ((size - 48) == internalsizev2) - yread(&check, (void *)SmpcInternalVars, internalsizev2, 1, fp); - else if ((size - 48) == 24) - yread(&check, (void *)SmpcInternalVars, 24, 1, fp); - else - fseek(fp, size - 48, SEEK_CUR); - } - else if (version == 2) - yread(&check, (void *)SmpcInternalVars, internalsizev2, 1, fp); - else - yread(&check, (void *)SmpcInternalVars, sizeof(SmpcInternal), 1, fp); - - // Read ID's of currently emulated peripherals(fix me) - - return size; -} - -////////////////////////////////////////////////////////////////////////////// - + // Return non-peripheral data + SmpcInternalVars->firstPeri = 1; + SmpcInternalVars->intback = (SmpcRegs->IREG[1] & 0x8) >> 3; // does the program want peripheral data too? + SmpcINTBACKStatus(); + SmpcRegs->SR = 0x4F | (SmpcInternalVars->intback << 5); // the low nibble is undefined(or 0xF) + ScuSendSystemManager(); + return; + } + if (SmpcRegs->IREG[1] & 0x8) { + SmpcInternalVars->firstPeri = 1; + SmpcInternalVars->intback = 1; + SmpcRegs->SR = 0x40; + SmpcINTBACKPeripheral(); + SmpcRegs->OREG[31] = 0x10; // may need to be changed + ScuSendSystemManager(); + return; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcINTBACKEnd(void) { + SmpcInternalVars->intback = 0; +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSETSMEM(void) { + int i; + + for(i = 0;i < 4;i++) + SmpcInternalVars->SMEM[i] = SmpcRegs->IREG[i]; + + SmpcRegs->OREG[31] = 0x17; +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcNMIREQ(void) { + SH2SendInterrupt(MSH2, 0xB, 16); + SmpcRegs->OREG[31] = 0x18; +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcResetButton(void) { + // If RESD isn't set, send an NMI request to the MSH2. + if (SmpcInternalVars->resd) + return; + + SH2SendInterrupt(MSH2, 0xB, 16); +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcRESENAB(void) { + SmpcInternalVars->resd = 0; + SmpcRegs->OREG[31] = 0x19; +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcRESDISA(void) { + SmpcInternalVars->resd = 1; + SmpcRegs->OREG[31] = 0x1A; +} + +////////////////////////////////////////////////////////////////////////////// + +void SmpcExec(s32 t) { + if (SmpcInternalVars->timing > 0) { + SmpcInternalVars->timing -= t; + if (SmpcInternalVars->timing <= 0) { + switch(SmpcRegs->COMREG) { + case 0x0: + SMPCLOG("smpc\t: MSHON not implemented\n"); + break; + case 0x2: + SMPCLOG("smpc\t: SSHON\n"); + SmpcSSHON(); + break; + case 0x3: + SMPCLOG("smpc\t: SSHOFF\n"); + SmpcSSHOFF(); + break; + case 0x6: + SMPCLOG("smpc\t: SNDON\n"); + SmpcSNDON(); + break; + case 0x7: + SMPCLOG("smpc\t: SNDOFF\n"); + SmpcSNDOFF(); + break; + case 0x8: + SMPCLOG("smpc\t: CDON not implemented\n"); + break; + case 0x9: + SMPCLOG("smpc\t: CDOFF not implemented\n"); + break; + case 0xD: + SMPCLOG("smpc\t: SYSRES not implemented\n"); + break; + case 0xE: + SMPCLOG("smpc\t: CKCHG352\n"); + SmpcCKCHG352(); + break; + case 0xF: + SMPCLOG("smpc\t: CKCHG320\n"); + SmpcCKCHG320(); + break; + case 0x10: + SMPCLOG("smpc\t: INTBACK\n"); + SmpcINTBACK(); + break; + case 0x17: + SMPCLOG("smpc\t: SETSMEM\n"); + SmpcSETSMEM(); + break; + case 0x18: + SMPCLOG("smpc\t: NMIREQ\n"); + SmpcNMIREQ(); + break; + case 0x19: + SMPCLOG("smpc\t: RESENAB\n"); + SmpcRESENAB(); + break; + case 0x1A: + SMPCLOG("smpc\t: RESDISA\n"); + SmpcRESDISA(); + break; + default: + SMPCLOG("smpc\t: Command %02X not implemented\n", SmpcRegs->COMREG); + break; + } + + SmpcRegs->SF = 0; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +u8 FASTCALL SmpcReadByte(u32 addr) { + addr &= 0x7F; + + return SmpcRegsT[addr >> 1]; +} + +////////////////////////////////////////////////////////////////////////////// + +u16 FASTCALL SmpcReadWord(USED_IF_SMPC_DEBUG u32 addr) { + // byte access only + SMPCLOG("smpc\t: SMPC register read word - %08X\n", addr); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +u32 FASTCALL SmpcReadLong(USED_IF_SMPC_DEBUG u32 addr) { + // byte access only + SMPCLOG("smpc\t: SMPC register read long - %08X\n", addr); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +static void SmpcSetTiming(void) { + switch(SmpcRegs->COMREG) { + case 0x0: + SMPCLOG("smpc\t: MSHON not implemented\n"); + SmpcInternalVars->timing = 1; + return; + case 0x8: + SMPCLOG("smpc\t: CDON not implemented\n"); + SmpcInternalVars->timing = 1; + return; + case 0x9: + SMPCLOG("smpc\t: CDOFF not implemented\n"); + SmpcInternalVars->timing = 1; + return; + case 0xD: + case 0xE: + case 0xF: + SmpcInternalVars->timing = 1; // this has to be tested on a real saturn + return; + case 0x10: + if (SmpcInternalVars->intback) + SmpcInternalVars->timing = 20; // this will need to be verified + else { + // Calculate timing based on what data is being retrieved + + SmpcInternalVars->timing = 1; + + // If retrieving non-peripheral data, add 0.2 milliseconds + if (SmpcRegs->IREG[0] == 0x01) + SmpcInternalVars->timing += 2; + + // If retrieving peripheral data, add 15 milliseconds + if (SmpcRegs->IREG[1] & 0x8) + SmpcInternalVars->timing += 16000; // Strangely enough, this works better +// SmpcInternalVars->timing += 150; + } + return; + case 0x17: + SmpcInternalVars->timing = 1; + return; + case 0x2: + SmpcInternalVars->timing = 1; + return; + case 0x3: + SmpcInternalVars->timing = 1; + return; + case 0x6: + case 0x7: + case 0x18: + case 0x19: + case 0x1A: + SmpcInternalVars->timing = 1; + return; + default: + SMPCLOG("smpc\t: unimplemented command: %02X\n", SmpcRegs->COMREG); + SmpcRegs->SF = 0; + break; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void FASTCALL SmpcWriteByte(u32 addr, u8 val) { + addr &= 0x7F; + SmpcRegsT[addr >> 1] = val; + + switch(addr) { + case 0x01: // Maybe an INTBACK continue/break request + if (SmpcInternalVars->intback) + { + if (SmpcRegs->IREG[0] & 0x40) { + // Break + SmpcInternalVars->intback = 0; + SmpcRegs->SR &= 0x0F; + break; + } + else if (SmpcRegs->IREG[0] & 0x80) { + // Continue + SmpcRegs->COMREG = 0x10; + SmpcSetTiming(); + SmpcRegs->SF = 1; + } + } + return; + case 0x1F: + SmpcSetTiming(); + return; + case 0x63: + SmpcRegs->SF &= 0x1; + return; + case 0x75: + // FIX ME (should support other peripherals) + + switch (SmpcRegs->DDR[0] & 0x7F) { // Which Control Method do we use? + case 0x40: + SMPCLOG("smpc\t: Peripheral TH Control Method not implemented\n"); + break; + case 0x60: + switch (val & 0x60) { + case 0x60: // 1st Data + val = (val & 0x80) | 0x14 | (PORTDATA1.data[1] & 0x8); + break; + case 0x20: // 2nd Data + val = (val & 0x80) | 0x10 | ((PORTDATA1.data[2] >> 4) & 0xF); + break; + case 0x40: // 3rd Data + val = (val & 0x80) | 0x10 | (PORTDATA1.data[2] & 0xF); + break; + case 0x00: // 4th Data + val = (val & 0x80) | 0x10 | ((PORTDATA1.data[1] >> 4) & 0xF); + break; + default: break; + } + + SmpcRegs->PDR[0] = val; + break; + default: + SMPCLOG("smpc\t: Peripheral Unknown Control Method not implemented\n"); + break; + } + + return; + default: + return; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void FASTCALL SmpcWriteWord(USED_IF_SMPC_DEBUG u32 addr, UNUSED u16 val) { + // byte access only + SMPCLOG("smpc\t: SMPC register write word - %08X\n", addr); +} + +////////////////////////////////////////////////////////////////////////////// + +void FASTCALL SmpcWriteLong(USED_IF_SMPC_DEBUG u32 addr, UNUSED u32 val) { + // byte access only + SMPCLOG("smpc\t: SMPC register write long - %08X\n", addr); +} + +////////////////////////////////////////////////////////////////////////////// + +int SmpcSaveState(FILE *fp) +{ + int offset; + IOCheck_struct check; + + offset = StateWriteHeader(fp, "SMPC", 3); + + // Write registers + ywrite(&check, (void *)SmpcRegs->IREG, sizeof(u8), 7, fp); + ywrite(&check, (void *)&SmpcRegs->COMREG, sizeof(u8), 1, fp); + ywrite(&check, (void *)SmpcRegs->OREG, sizeof(u8), 32, fp); + ywrite(&check, (void *)&SmpcRegs->SR, sizeof(u8), 1, fp); + ywrite(&check, (void *)&SmpcRegs->SF, sizeof(u8), 1, fp); + ywrite(&check, (void *)SmpcRegs->PDR, sizeof(u8), 2, fp); + ywrite(&check, (void *)SmpcRegs->DDR, sizeof(u8), 2, fp); + ywrite(&check, (void *)&SmpcRegs->IOSEL, sizeof(u8), 1, fp); + ywrite(&check, (void *)&SmpcRegs->EXLE, sizeof(u8), 1, fp); + + // Write internal variables + ywrite(&check, (void *)SmpcInternalVars, sizeof(SmpcInternal), 1, fp); + + // Write ID's of currently emulated peripherals(fix me) + + return StateFinishHeader(fp, offset); +} + +////////////////////////////////////////////////////////////////////////////// + +int SmpcLoadState(FILE *fp, int version, int size) +{ + IOCheck_struct check; + int internalsizev2 = sizeof(SmpcInternal) - 8; + + // Read registers + yread(&check, (void *)SmpcRegs->IREG, sizeof(u8), 7, fp); + yread(&check, (void *)&SmpcRegs->COMREG, sizeof(u8), 1, fp); + yread(&check, (void *)SmpcRegs->OREG, sizeof(u8), 32, fp); + yread(&check, (void *)&SmpcRegs->SR, sizeof(u8), 1, fp); + yread(&check, (void *)&SmpcRegs->SF, sizeof(u8), 1, fp); + yread(&check, (void *)SmpcRegs->PDR, sizeof(u8), 2, fp); + yread(&check, (void *)SmpcRegs->DDR, sizeof(u8), 2, fp); + yread(&check, (void *)&SmpcRegs->IOSEL, sizeof(u8), 1, fp); + yread(&check, (void *)&SmpcRegs->EXLE, sizeof(u8), 1, fp); + + // Read internal variables + if (version == 1) + { + // This handles the problem caused by the version not being incremented + // when SmpcInternal was changed + if ((size - 48) == internalsizev2) + yread(&check, (void *)SmpcInternalVars, internalsizev2, 1, fp); + else if ((size - 48) == 24) + yread(&check, (void *)SmpcInternalVars, 24, 1, fp); + else + fseek(fp, size - 48, SEEK_CUR); + } + else if (version == 2) + yread(&check, (void *)SmpcInternalVars, internalsizev2, 1, fp); + else + yread(&check, (void *)SmpcInternalVars, sizeof(SmpcInternal), 1, fp); + + // Read ID's of currently emulated peripherals(fix me) + + return size; +} + +////////////////////////////////////////////////////////////////////////////// +