X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fmisc.c;h=889639d668b79c3f2576cb36ae41fd09210ec46b;hp=034e5e0a398d36d82e64b447730d7b595d44b09e;hb=HEAD;hpb=ddbaf678c49d33cf60f1eac5069e3275baa2c685 diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index 034e5e0a..889639d6 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -21,14 +21,21 @@ * Miscellaneous functions, including savestates and CD-ROM loading. */ +#include +#include +#include #include "misc.h" #include "cdrom.h" #include "mdec.h" #include "gpu.h" #include "ppf.h" +#include "psxbios.h" +#include "database.h" +#include char CdromId[10] = ""; char CdromLabel[33] = ""; +int CdromFrontendId; // for frontend use // PSX Executable types #define PSX_EXE 1 @@ -52,16 +59,11 @@ struct iso_directory_record { char name [1]; }; -void mmssdd( char *b, char *p ) +static void mmssdd( char *b, char *p ) { int m, s, d; -#if defined(__arm__) - int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; -#elif defined(__BIGENDIAN__) - int block = (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | (b[3] << 24); -#else - int block = *((int*)b); -#endif + unsigned char *ub = (void *)b; + int block = (ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0]; block += 150; m = block / 4500; // minutes @@ -71,7 +73,7 @@ void mmssdd( char *b, char *p ) m = ((m / 10) << 4) | m % 10; s = ((s / 10) << 4) | s % 10; - d = ((d / 10) << 4) | d % 10; + d = ((d / 10) << 4) | d % 10; p[0] = m; p[1] = s; @@ -92,9 +94,10 @@ void mmssdd( char *b, char *p ) time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]); #define READTRACK() \ - if (CDR_readTrack(time) == -1) return -1; \ - buf = CDR_getBuffer(); \ - if (buf == NULL) return -1; else CheckPPFCache(buf, time[0], time[1], time[2]); + if (!CDR_readTrack(time)) return -1; \ + buf = (void *)CDR_getBuffer(); \ + if (buf == NULL) return -1; \ + else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]); #define READDIR(_dir) \ READTRACK(); \ @@ -104,14 +107,15 @@ void mmssdd( char *b, char *p ) READTRACK(); \ memcpy(_dir + 2048, buf + 12, 2048); -int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) { +int GetCdromFile(u8 *mdir, u8 *time, char *filename) { struct iso_directory_record *dir; - char ddir[4096]; + int retval = -1; + u8 ddir[4096]; u8 *buf; int i; // only try to scan if a filename is given - if (!strlen(filename)) return -1; + if (filename == INVALID_PTR || !strlen(filename)) return -1; i = 0; while (i < 4096) { @@ -119,7 +123,7 @@ int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) { if (dir->length[0] == 0) { return -1; } - i += dir->length[0]; + i += (u8)dir->length[0]; if (dir->flags[0] & 0x2) { // it's a dir if (!strnicmp((char *)&dir->name[0], filename, dir->name_len[0])) { @@ -135,23 +139,81 @@ int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) { } else { if (!strnicmp((char *)&dir->name[0], filename, strlen(filename))) { mmssdd(dir->extent, (char *)time); + retval = 0; break; } } } - return 0; + return retval; +} + +static void SetBootRegs(u32 pc, u32 gp, u32 sp) +{ + //printf("%s %08x %08x %08x\n", __func__, pc, gp, sp); + psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL); + + psxRegs.pc = pc; + psxRegs.GPR.n.gp = gp; + psxRegs.GPR.n.sp = sp ? sp : 0x801fff00; + psxRegs.GPR.n.fp = psxRegs.GPR.n.sp; + + psxRegs.GPR.n.t0 = psxRegs.GPR.n.sp; // mimic A(43) + psxRegs.GPR.n.t3 = pc; + + psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); +} + +int BiosBootBypass() { + struct CdrStat stat = { 0, 0, }; + assert(psxRegs.pc == 0x80030000); + + // no bypass if the lid is open + CDR__getStatus(&stat); + if (stat.Status & 0x10) + return 0; + + // skip BIOS logos and region check + psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL); + psxRegs.pc = psxRegs.GPR.n.ra; + return 1; +} + +static void getFromCnf(char *buf, const char *key, u32 *val) +{ + buf = strstr(buf, key); + if (buf) + buf = strchr(buf, '='); + if (buf) { + unsigned long v; + errno = 0; + v = strtoul(buf + 1, NULL, 16); + if (errno == 0) + *val = v; + } } int LoadCdrom() { - EXE_HEADER tmpHead; + union { + EXE_HEADER h; + u32 d[sizeof(EXE_HEADER) / sizeof(u32)]; + } tmpHead; struct iso_directory_record *dir; u8 time[4], *buf; u8 mdir[4096]; - s8 exename[256]; + char exename[256]; + u32 cnf_tcb = 4; + u32 cnf_event = 16; + u32 cnf_stack = 0; + u32 t_addr; + u32 t_size; + u32 sp = 0; + int i, ret; if (!Config.HLE) { - psxRegs.pc = psxRegs.GPR.n.ra; - return 0; + if (psxRegs.pc != 0x80030000) // BiosBootBypass'ed or custom BIOS? + return 0; + if (Config.SlowBoot) + return 0; } time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); @@ -159,7 +221,7 @@ int LoadCdrom() { READTRACK(); // skip head and sub, and go to the root directory record - dir = (struct iso_directory_record*) &buf[12+156]; + dir = (struct iso_directory_record*) &buf[12+156]; mmssdd(dir->extent, (char*)time); @@ -169,18 +231,20 @@ int LoadCdrom() { if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) { // if SYSTEM.CNF is missing, start an existing PSX.EXE if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1; + strcpy(exename, "PSX.EXE;1"); READTRACK(); } else { // read the SYSTEM.CNF READTRACK(); + buf[1023] = 0; - sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename); - if (GetCdromFile(mdir, time, exename) == -1) { - sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename); - if (GetCdromFile(mdir, time, exename) == -1) { - char *ptr = strstr(buf + 12, "cdrom:"); + ret = sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename); + if (ret < 1 || GetCdromFile(mdir, time, exename) == -1) { + ret = sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename); + if (ret < 1 || GetCdromFile(mdir, time, exename) == -1) { + char *ptr = strstr((char *)buf + 12, "cdrom:"); if (ptr != NULL) { ptr += 6; while (*ptr == '\\' || *ptr == '/') ptr++; @@ -195,53 +259,73 @@ int LoadCdrom() { return -1; } } + getFromCnf((char *)buf + 12, "TCB", &cnf_tcb); + getFromCnf((char *)buf + 12, "EVENT", &cnf_event); + getFromCnf((char *)buf + 12, "STACK", &cnf_stack); + if (Config.HLE) + psxBiosCnfLoaded(cnf_tcb, cnf_event, cnf_stack); // Read the EXE-Header READTRACK(); } memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER)); + for (i = 2; i < sizeof(tmpHead.d) / sizeof(tmpHead.d[0]); i++) + tmpHead.d[i] = SWAP32(tmpHead.d[i]); - psxRegs.pc = SWAP32(tmpHead.pc0); - psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0); - psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); - if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00; - - tmpHead.t_size = SWAP32(tmpHead.t_size); - tmpHead.t_addr = SWAP32(tmpHead.t_addr); - - psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4); + SysPrintf("manual booting '%s' pc=%x\n", exename, tmpHead.h.pc0); + sp = tmpHead.h.s_addr; + if (cnf_stack) + sp = cnf_stack; + SetBootRegs(tmpHead.h.pc0, tmpHead.h.gp0, sp); // Read the rest of the main executable - while (tmpHead.t_size & ~2047) { - void *ptr = (void *)PSXM(tmpHead.t_addr); + for (t_addr = tmpHead.h.t_addr, t_size = tmpHead.h.t_size; t_size & ~2047; ) { + void *ptr = (void *)PSXM(t_addr); incTime(); READTRACK(); - if (ptr != NULL) memcpy(ptr, buf+12, 2048); + if (ptr != INVALID_PTR) memcpy(ptr, buf+12, 2048); - tmpHead.t_size -= 2048; - tmpHead.t_addr += 2048; + t_addr += 2048; + t_size -= 2048; } + psxCpu->Clear(tmpHead.h.t_addr, tmpHead.h.t_size / 4); + //psxCpu->Reset(); + + if (Config.HLE) + psxBiosCheckExe(tmpHead.h.t_addr, tmpHead.h.t_size, 0); + return 0; } -int LoadCdromFile(const char *filename, EXE_HEADER *head) { +int LoadCdromFile(const char *filename, EXE_HEADER *head, u8 *time_bcd_out) { struct iso_directory_record *dir; u8 time[4],*buf; - u8 mdir[4096], exename[256]; + u8 mdir[4096]; + char exename[256]; + const char *p1, *p2; u32 size, addr; + void *mem; + + if (filename == INVALID_PTR) + return -1; - sscanf(filename, "cdrom:\\%256s", exename); + p1 = filename; + if ((p2 = strchr(p1, ':'))) + p1 = p2 + 1; + while (*p1 == '\\') + p1++; + snprintf(exename, sizeof(exename), "%s", p1); time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); READTRACK(); // skip head and sub, and go to the root directory record - dir = (struct iso_directory_record *)&buf[12 + 156]; + dir = (struct iso_directory_record *)&buf[12 + 156]; mmssdd(dir->extent, (char*)time); @@ -250,48 +334,62 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) { if (GetCdromFile(mdir, time, exename) == -1) return -1; READTRACK(); + incTime(); memcpy(head, buf + 12, sizeof(EXE_HEADER)); - size = head->t_size; - addr = head->t_addr; + size = SWAP32(head->t_size); + addr = SWAP32(head->t_addr); psxCpu->Clear(addr, size / 4); + //psxCpu->Reset(); while (size & ~2047) { - incTime(); READTRACK(); + incTime(); - memcpy((void *)PSXM(addr), buf + 12, 2048); + mem = PSXM(addr); + if (mem != INVALID_PTR) + memcpy(mem, buf + 12, 2048); size -= 2048; addr += 2048; } + if (time_bcd_out) + memcpy(time_bcd_out, time, 3); return 0; } int CheckCdrom() { struct iso_directory_record *dir; - unsigned char time[4], *buf; + struct CdrStat stat = { 0, 0, }; + unsigned char time[4]; + char *buf; unsigned char mdir[4096]; char exename[256]; - int i, c; + int i, len, c; FreePPFCache(); + memset(CdromLabel, 0, sizeof(CdromLabel)); + memset(CdromId, 0, sizeof(CdromId)); + memset(exename, 0, sizeof(exename)); time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + if (!Config.HLE && Config.SlowBoot) { + // boot to BIOS in case of CDDA ir lid open + CDR_getStatus(&stat); + if ((stat.Status & 0x10) || stat.Type == 2 || !CDR_readTrack(time)) + return 0; + } READTRACK(); - CdromLabel[0] = '\0'; - CdromId[0] = '\0'; - strncpy(CdromLabel, buf + 52, 32); // skip head and sub, and go to the root directory record - dir = (struct iso_directory_record *)&buf[12 + 156]; + dir = (struct iso_directory_record *)&buf[12 + 156]; mmssdd(dir->extent, (char *)time); @@ -300,9 +398,9 @@ int CheckCdrom() { if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) { READTRACK(); - sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename); + sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename); if (GetCdromFile(mdir, time, exename) == -1) { - sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename); + sscanf(buf + 12, "BOOT = cdrom:%255s", exename); if (GetCdromFile(mdir, time, exename) == -1) { char *ptr = strstr(buf + 12, "cdrom:"); // possibly the executable is in some subdir if (ptr != NULL) { @@ -319,6 +417,14 @@ int CheckCdrom() { return -1; } } + /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */ + if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') { + size_t offset = 4; + size_t i, len = strlen(exename) - offset; + for (i = 0; i < len; i++) + exename[i] = exename[i + offset]; + exename[i] = '\0'; + } } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) { strcpy(exename, "PSX.EXE;1"); strcpy(CdromId, "SLUS99999"); @@ -326,19 +432,27 @@ int CheckCdrom() { return -1; // SYSTEM.CNF and PSX.EXE not found if (CdromId[0] == '\0') { - i = strlen(exename); - if (i >= 2) { - if (exename[i - 2] == ';') i-= 2; - c = 8; i--; - while (i >= 0 && c >= 0) { - if (isalnum(exename[i])) CdromId[c--] = exename[i]; - i--; - } + len = strlen(exename); + c = 0; + for (i = 0; i < len; ++i) { + if (exename[i] == ';' || c >= sizeof(CdromId) - 1) + break; + if (isalnum(exename[i])) + CdromId[c++] = exename[i]; } } + if (CdromId[0] == '\0') + strcpy(CdromId, "SLUS99999"); + if (Config.PsxAuto) { // autodetect system (pal or ntsc) - if (CdromId[2] == 'e' || CdromId[2] == 'E') + if ( + /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */ + ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) || + !strncmp(CdromId, "DTLS3035", 8) || + !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL + !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID; + !strncmp(CdromId, "PBPX95008", 9)) // add more serials if they are discovered. Config.PsxType = PSX_TYPE_PAL; // pal else Config.PsxType = PSX_TYPE_NTSC; // ntsc } @@ -348,6 +462,9 @@ int CheckCdrom() { } SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel); SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId); + SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename); + + Apply_Hacks_Cdrom(); BuildPPFCache(); @@ -362,7 +479,9 @@ static int PSXGetFileType(FILE *f) { current = ftell(f); fseek(f, 0L, SEEK_SET); - fread(mybuf, 2048, 1, f); + if (fread(&mybuf, 1, sizeof(mybuf), f) != sizeof(mybuf)) + goto io_fail; + fseek(f, current, SEEK_SET); exe_hdr = (EXE_HEADER *)mybuf; @@ -377,6 +496,28 @@ static int PSXGetFileType(FILE *f) { return COFF_EXE; return INVALID_EXE; + +io_fail: +#ifndef NDEBUG + SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__); +#endif + return INVALID_EXE; +} + +// temporary pandora workaround.. +// FIXME: remove +size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + void *tmp; + size_t ret = 0; + + tmp = malloc(size * nmemb); + if (tmp) { + ret = fread(tmp, size, nmemb, stream); + memcpy(ptr, tmp, size * nmemb); + free(tmp); + } + return ret; } int Load(const char *ExePath) { @@ -388,8 +529,8 @@ int Load(const char *ExePath) { u32 section_address, section_size; void *mem; - strncpy(CdromId, "SLUS99999", 9); - strncpy(CdromLabel, "SLUS_999.99", 11); + strcpy(CdromId, "SLUS99999"); + strcpy(CdromLabel, "SLUS_999.99"); tmpFile = fopen(ExePath, "rb"); if (tmpFile == NULL) { @@ -399,45 +540,46 @@ int Load(const char *ExePath) { type = PSXGetFileType(tmpFile); switch (type) { case PSX_EXE: - fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile); + if (fread(&tmpHead, 1, sizeof(EXE_HEADER), tmpFile) != sizeof(EXE_HEADER)) + goto fail_io; section_address = SWAP32(tmpHead.t_addr); section_size = SWAP32(tmpHead.t_size); mem = PSXM(section_address); - if (mem != NULL) { - fseek(tmpFile, 0x800, SEEK_SET); - fread(mem, section_size, 1, tmpFile); + if (mem != INVALID_PTR) { + fseek(tmpFile, 0x800, SEEK_SET); + fread_to_ram(mem, section_size, 1, tmpFile); psxCpu->Clear(section_address, section_size / 4); } - fclose(tmpFile); - psxRegs.pc = SWAP32(tmpHead.pc0); - psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0); - psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); - if (psxRegs.GPR.n.sp == 0) - psxRegs.GPR.n.sp = 0x801fff00; + SetBootRegs(SWAP32(tmpHead.pc0), SWAP32(tmpHead.gp0), + SWAP32(tmpHead.s_addr)); retval = 0; break; case CPE_EXE: fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */ do { - fread(&opcode, 1, 1, tmpFile); + if (fread(&opcode, 1, sizeof(opcode), tmpFile) != sizeof(opcode)) + goto fail_io; switch (opcode) { case 1: /* Section loading */ - fread(§ion_address, 4, 1, tmpFile); - fread(§ion_size, 4, 1, tmpFile); + if (fread(§ion_address, 1, sizeof(section_address), tmpFile) != sizeof(section_address)) + goto fail_io; + if (fread(§ion_size, 1, sizeof(section_size), tmpFile) != sizeof(section_size)) + goto fail_io; section_address = SWAPu32(section_address); section_size = SWAPu32(section_size); #ifdef EMU_LOG EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address); #endif mem = PSXM(section_address); - if (mem != NULL) { - fread(mem, section_size, 1, tmpFile); + if (mem != INVALID_PTR) { + fread_to_ram(mem, section_size, 1, tmpFile); psxCpu->Clear(section_address, section_size / 4); } break; case 3: /* register loading (PC only?) */ fseek(tmpFile, 2, SEEK_CUR); /* unknown field */ - fread(&psxRegs.pc, 4, 1, tmpFile); + if (fread(&psxRegs.pc, 1, sizeof(psxRegs.pc), tmpFile) != sizeof(psxRegs.pc)) + goto fail_io; psxRegs.pc = SWAPu32(psxRegs.pc); break; case 0: /* End of file */ @@ -454,7 +596,8 @@ int Load(const char *ExePath) { retval = -1; break; case INVALID_EXE: - SysPrintf(_("This file does not appear to be a valid PSX file.\n")); + SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n")); + SysPrintf(_("(did you forget -cdfile ?)\n")); retval = -1; break; } @@ -465,126 +608,215 @@ int Load(const char *ExePath) { CdromLabel[0] = '\0'; } + if (tmpFile) + fclose(tmpFile); return retval; + +fail_io: +#ifndef NDEBUG + SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__); +#endif + fclose(tmpFile); + return -1; } // STATES -static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION; +static void *zlib_open(const char *name, const char *mode) +{ + return gzopen(name, mode); +} + +static int zlib_read(void *file, void *buf, u32 len) +{ + return gzread(file, buf, len); +} + +static int zlib_write(void *file, const void *buf, u32 len) +{ + return gzwrite(file, buf, len); +} + +static long zlib_seek(void *file, long offs, int whence) +{ + return gzseek(file, offs, whence); +} + +static void zlib_close(void *file) +{ + gzclose(file); +} + +struct PcsxSaveFuncs SaveFuncs = { + zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close +}; + +static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION; // Savestate Versioning! // If you make changes to the savestate version, please increment the value below. static const u32 SaveVersion = 0x8b410006; +#define MISC_MAGIC 0x4353494d +struct misc_save_data { + u32 magic; + u32 gteBusyCycle; + u32 muldivBusyCycle; + u32 biuReg; + u32 biosBranchCheck; + u32 gpuIdleAfter; + u32 gpuSr; + u32 frame_counter; + int CdromFrontendId; +}; + int SaveState(const char *file) { - gzFile f; - GPUFreeze_t *gpufP; - SPUFreeze_t *spufP; + struct misc_save_data *misc = (void *)(psxH + 0xf000); + void *f; + GPUFreeze_t *gpufP = NULL; + SPUFreezeHdr_t spufH; + SPUFreeze_t *spufP = NULL; + unsigned char *pMem = NULL; + int result = -1; int Size; - unsigned char *pMem; - f = gzopen(file, "wb"); + assert(!psxRegs.branching); + assert(!psxRegs.cpuInRecursion); + assert(!misc->magic); + + f = SaveFuncs.open(file, "wb"); if (f == NULL) return -1; - new_dyna_save(); + misc->magic = MISC_MAGIC; + misc->gteBusyCycle = psxRegs.gteBusyCycle; + misc->muldivBusyCycle = psxRegs.muldivBusyCycle; + misc->biuReg = psxRegs.biuReg; + misc->biosBranchCheck = psxRegs.biosBranchCheck; + misc->gpuIdleAfter = psxRegs.gpuIdleAfter; + misc->gpuSr = HW_GPU_STATUS; + misc->frame_counter = frame_counter; + misc->CdromFrontendId = CdromFrontendId; + + psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL); - gzwrite(f, (void *)PcsxHeader, 32); - gzwrite(f, (void *)&SaveVersion, sizeof(u32)); - gzwrite(f, (void *)&Config.HLE, sizeof(boolean)); + SaveFuncs.write(f, (void *)PcsxHeader, 32); + SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32)); + SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean)); pMem = (unsigned char *)malloc(128 * 96 * 3); - if (pMem == NULL) return -1; + if (pMem == NULL) goto cleanup; GPU_getScreenPic(pMem); - gzwrite(f, pMem, 128 * 96 * 3); + SaveFuncs.write(f, pMem, 128 * 96 * 3); free(pMem); if (Config.HLE) psxBiosFreeze(1); - gzwrite(f, psxM, 0x00200000); - gzwrite(f, psxR, 0x00080000); - gzwrite(f, psxH, 0x00010000); - gzwrite(f, (void *)&psxRegs, sizeof(psxRegs)); + SaveFuncs.write(f, psxM, 0x00200000); + SaveFuncs.write(f, psxR, 0x00080000); + SaveFuncs.write(f, psxH, 0x00010000); + // only partial save of psxRegisters to maintain savestate compat + SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle)); // gpu gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t)); + if (gpufP == NULL) goto cleanup; gpufP->ulFreezeVersion = 1; GPU_freeze(1, gpufP); - gzwrite(f, gpufP, sizeof(GPUFreeze_t)); - free(gpufP); + SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t)); + free(gpufP); gpufP = NULL; // spu - spufP = (SPUFreeze_t *) malloc(16); - SPU_freeze(2, spufP); - Size = spufP->Size; gzwrite(f, &Size, 4); - free(spufP); + SPU_freeze(2, (SPUFreeze_t *)&spufH, psxRegs.cycle); + Size = spufH.Size; SaveFuncs.write(f, &Size, 4); spufP = (SPUFreeze_t *) malloc(Size); - SPU_freeze(1, spufP); - gzwrite(f, spufP, Size); - free(spufP); + if (spufP == NULL) goto cleanup; + SPU_freeze(1, spufP, psxRegs.cycle); + SaveFuncs.write(f, spufP, Size); + free(spufP); spufP = NULL; sioFreeze(f, 1); cdrFreeze(f, 1); psxHwFreeze(f, 1); psxRcntFreeze(f, 1); mdecFreeze(f, 1); - - gzclose(f); - - new_dyna_after_save(); - - return 0; + new_dyna_freeze(f, 1); + padFreeze(f, 1); + + result = 0; +cleanup: + memset(misc, 0, sizeof(*misc)); + SaveFuncs.close(f); + return result; } int LoadState(const char *file) { - gzFile f; - GPUFreeze_t *gpufP; - SPUFreeze_t *spufP; + struct misc_save_data *misc = (void *)(psxH + 0xf000); + u32 biosBranchCheckOld = psxRegs.biosBranchCheck; + void *f; + GPUFreeze_t *gpufP = NULL; + SPUFreeze_t *spufP = NULL; int Size; char header[32]; u32 version; boolean hle; + int result = -1; - f = gzopen(file, "rb"); + f = SaveFuncs.open(file, "rb"); if (f == NULL) return -1; - gzread(f, header, sizeof(header)); - gzread(f, &version, sizeof(u32)); - gzread(f, &hle, sizeof(boolean)); + SaveFuncs.read(f, header, sizeof(header)); + SaveFuncs.read(f, &version, sizeof(u32)); + SaveFuncs.read(f, &hle, sizeof(boolean)); if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) { - gzclose(f); - return -1; + SysPrintf("incompatible savestate version %x\n", version); + goto cleanup; } Config.HLE = hle; if (Config.HLE) psxBiosInit(); - psxCpu->Reset(); - gzseek(f, 128 * 96 * 3, SEEK_CUR); + SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR); + SaveFuncs.read(f, psxM, 0x00200000); + SaveFuncs.read(f, psxR, 0x00080000); + SaveFuncs.read(f, psxH, 0x00010000); + SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle)); + psxRegs.gteBusyCycle = psxRegs.cycle; + psxRegs.biosBranchCheck = ~0; + psxRegs.gpuIdleAfter = psxRegs.cycle - 1; + HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY); + if (misc->magic == MISC_MAGIC) { + psxRegs.gteBusyCycle = misc->gteBusyCycle; + psxRegs.muldivBusyCycle = misc->muldivBusyCycle; + psxRegs.biuReg = misc->biuReg; + psxRegs.biosBranchCheck = misc->biosBranchCheck; + psxRegs.gpuIdleAfter = misc->gpuIdleAfter; + HW_GPU_STATUS = misc->gpuSr; + frame_counter = misc->frame_counter; + CdromFrontendId = misc->CdromFrontendId; + } - gzread(f, psxM, 0x00200000); - gzread(f, psxR, 0x00080000); - gzread(f, psxH, 0x00010000); - gzread(f, (void *)&psxRegs, sizeof(psxRegs)); + psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); if (Config.HLE) psxBiosFreeze(0); // gpu gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t)); - gzread(f, gpufP, sizeof(GPUFreeze_t)); + if (gpufP == NULL) goto cleanup; + SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t)); GPU_freeze(0, gpufP); free(gpufP); - if (HW_GPU_STATUS == 0) - HW_GPU_STATUS = GPU_readStatus(); + gpuSyncPluginSR(); // spu - gzread(f, &Size, 4); + SaveFuncs.read(f, &Size, 4); spufP = (SPUFreeze_t *)malloc(Size); - gzread(f, spufP, Size); - SPU_freeze(0, spufP); + if (spufP == NULL) goto cleanup; + SaveFuncs.read(f, spufP, Size); + SPU_freeze(0, spufP, psxRegs.cycle); free(spufP); sioFreeze(f, 0); @@ -592,27 +824,34 @@ int LoadState(const char *file) { psxHwFreeze(f, 0); psxRcntFreeze(f, 0); mdecFreeze(f, 0); + new_dyna_freeze(f, 0); + padFreeze(f, 0); - gzclose(f); - new_dyna_restore(); + events_restore(); + if (Config.HLE) + psxBiosCheckExe(biosBranchCheckOld, 0x60, 1); - return 0; + result = 0; +cleanup: + memset(misc, 0, sizeof(*misc)); + SaveFuncs.close(f); + return result; } int CheckState(const char *file) { - gzFile f; + void *f; char header[32]; u32 version; boolean hle; - f = gzopen(file, "rb"); + f = SaveFuncs.open(file, "rb"); if (f == NULL) return -1; - gzread(f, header, sizeof(header)); - gzread(f, &version, sizeof(u32)); - gzread(f, &hle, sizeof(boolean)); + SaveFuncs.read(f, header, sizeof(header)); + SaveFuncs.read(f, &version, sizeof(u32)); + SaveFuncs.read(f, &hle, sizeof(boolean)); - gzclose(f); + SaveFuncs.close(f); if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) return -1; @@ -626,10 +865,13 @@ int SendPcsxInfo() { if (NET_recvData == NULL || NET_sendData == NULL) return 0; + boolean Sio_old = 0; + boolean SpuIrq_old = 0; + boolean RCntFix_old = 0; NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING); - NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING); - NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING); - NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING); + NET_sendData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING); + NET_sendData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING); + NET_sendData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING); NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING); NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING); @@ -642,19 +884,20 @@ int RecvPcsxInfo() { if (NET_recvData == NULL || NET_sendData == NULL) return 0; + boolean Sio_old = 0; + boolean SpuIrq_old = 0; + boolean RCntFix_old = 0; NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING); - NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING); - NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING); - NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING); + NET_recvData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING); + NET_recvData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING); + NET_recvData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING); NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING); - SysUpdate(); - tmp = Config.Cpu; NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING); if (tmp != Config.Cpu) { psxCpu->Shutdown(); -#ifdef PSXREC +#ifndef DRC_DISABLE if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt; else psxCpu = &psxRec; #else @@ -664,6 +907,7 @@ int RecvPcsxInfo() { SysClose(); return -1; } psxCpu->Reset(); + psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); } return 0;