adjust bios handling again
[pcsx_rearmed.git] / libpcsxcore / misc.c
index 2fe5600..223266b 100644 (file)
 * Miscellaneous functions, including savestates and CD-ROM loading.
 */
 
+#include <stddef.h>
+#include <assert.h>
 #include "misc.h"
 #include "cdrom.h"
 #include "mdec.h"
 #include "gpu.h"
 #include "ppf.h"
+#include "database.h"
+#include <zlib.h>
 
 char CdromId[10] = "";
 char CdromLabel[33] = "";
@@ -52,16 +56,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 +70,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 +91,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,9 +104,10 @@ 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;
 
@@ -119,7 +120,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,11 +136,12 @@ 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 const unsigned int gpu_ctl_def[] = {
@@ -153,7 +155,7 @@ static const unsigned int gpu_data_def[] = {
        0x02000000, 0x00000000, 0x01ff03ff,
 };
 
-static void fake_bios_gpu_setup(void)
+void BiosLikeGPUSetup()
 {
        int i;
 
@@ -162,6 +164,28 @@ static void fake_bios_gpu_setup(void)
 
        for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
                GPU_writeData(gpu_data_def[i]);
+
+       HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
+}
+
+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;
+
+       psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
+}
+
+void BiosBootBypass() {
+       assert(psxRegs.pc == 0x80030000);
+
+       // skip BIOS logos and region check
+       psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
+       psxRegs.pc = psxRegs.GPR.n.ra;
 }
 
 int LoadCdrom() {
@@ -169,16 +193,13 @@ int LoadCdrom() {
        struct iso_directory_record *dir;
        u8 time[4], *buf;
        u8 mdir[4096];
-       s8 exename[256];
-
-       // not the best place to do it, but since BIOS boot logo killer
-       // is just below, do it here
-       fake_bios_gpu_setup();
+       char exename[256];
 
        if (!Config.HLE) {
-               // skip BIOS logos
-               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);
@@ -186,7 +207,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);
 
@@ -196,6 +217,7 @@ 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();
        }
@@ -203,11 +225,11 @@ int LoadCdrom() {
                // read the SYSTEM.CNF
                READTRACK();
 
-               sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename);
+               sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
                if (GetCdromFile(mdir, time, exename) == -1) {
-                       sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
+                       sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
                        if (GetCdromFile(mdir, time, exename) == -1) {
-                               char *ptr = strstr(buf + 12, "cdrom:");
+                               char *ptr = strstr((char *)buf + 12, "cdrom:");
                                if (ptr != NULL) {
                                        ptr += 6;
                                        while (*ptr == '\\' || *ptr == '/') ptr++;
@@ -229,15 +251,14 @@ int LoadCdrom() {
 
        memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
 
-       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;
+       SysPrintf("manual booting '%s'\n", exename);
+       SetBootRegs(SWAP32(tmpHead.pc0), SWAP32(tmpHead.gp0), SWAP32(tmpHead.s_addr));
 
        tmpHead.t_size = SWAP32(tmpHead.t_size);
        tmpHead.t_addr = SWAP32(tmpHead.t_addr);
 
        psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
+       psxCpu->Reset();
 
        // Read the rest of the main executable
        while (tmpHead.t_size & ~2047) {
@@ -246,7 +267,7 @@ int LoadCdrom() {
                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;
@@ -258,17 +279,19 @@ int LoadCdrom() {
 int LoadCdromFile(const char *filename, EXE_HEADER *head) {
        struct iso_directory_record *dir;
        u8 time[4],*buf;
-       u8 mdir[4096], exename[256];
+       u8 mdir[4096];
+       char exename[256];
        u32 size, addr;
+       void *mem;
 
-       sscanf(filename, "cdrom:\\%256s", exename);
+       sscanf(filename, "cdrom:\\%255s", exename);
 
        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);
 
@@ -283,12 +306,15 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) {
        addr = head->t_addr;
 
        psxCpu->Clear(addr, size / 4);
+       psxCpu->Reset();
 
        while (size & ~2047) {
                incTime();
                READTRACK();
 
-               memcpy((void *)PSXM(addr), buf + 12, 2048);
+               mem = PSXM(addr);
+               if (mem != INVALID_PTR)
+                       memcpy(mem, buf + 12, 2048);
 
                size -= 2048;
                addr += 2048;
@@ -299,10 +325,11 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) {
 
 int CheckCdrom() {
        struct iso_directory_record *dir;
-       unsigned char time[4], *buf;
+       unsigned char time[4];
+       char *buf;
        unsigned char mdir[4096];
        char exename[256];
-       int i, c;
+       int i, len, c;
 
        FreePPFCache();
 
@@ -312,13 +339,14 @@ int CheckCdrom() {
 
        READTRACK();
 
-       CdromLabel[0] = '\0';
-       CdromId[0] = '\0';
+       memset(CdromLabel, 0, sizeof(CdromLabel));
+       memset(CdromId, 0, sizeof(CdromId));
+       memset(exename, 0, sizeof(exename));
 
        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);
 
@@ -327,9 +355,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) {
@@ -346,6 +374,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");
@@ -353,19 +389,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
        }
@@ -375,6 +419,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();
 
@@ -389,7 +436,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;
@@ -404,6 +453,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) {
@@ -415,8 +486,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) {
@@ -426,45 +497,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(&section_address, 4, 1, tmpFile);
-                                                       fread(&section_size, 4, 1, tmpFile);
+                                                       if (fread(&section_address, 1, sizeof(section_address), tmpFile) != sizeof(section_address))
+                                                               goto fail_io;
+                                                       if (fread(&section_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 */
@@ -481,7 +553,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;
                }
@@ -492,62 +565,102 @@ 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;
 
 int SaveState(const char *file) {
-       gzFile f;
+       void *f;
        GPUFreeze_t *gpufP;
+       SPUFreezeHdr_t *spufH;
        SPUFreeze_t *spufP;
        int Size;
        unsigned char *pMem;
 
-       f = gzopen(file, "wb");
+       f = SaveFuncs.open(file, "wb");
        if (f == NULL) return -1;
 
-       new_dyna_save();
+       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;
        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));
        gpufP->ulFreezeVersion = 1;
        GPU_freeze(1, gpufP);
-       gzwrite(f, gpufP, sizeof(GPUFreeze_t));
+       SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
        free(gpufP);
 
        // spu
-       spufP = (SPUFreeze_t *) malloc(16);
-       SPU_freeze(2, spufP);
-       Size = spufP->Size; gzwrite(f, &Size, 4);
-       free(spufP);
+       spufH = malloc(sizeof(*spufH));
+       SPU_freeze(2, (SPUFreeze_t *)spufH, psxRegs.cycle);
+       Size = spufH->Size; SaveFuncs.write(f, &Size, 4);
+       free(spufH);
        spufP = (SPUFreeze_t *) malloc(Size);
-       SPU_freeze(1, spufP);
-       gzwrite(f, spufP, Size);
+       SPU_freeze(1, spufP, psxRegs.cycle);
+       SaveFuncs.write(f, spufP, Size);
        free(spufP);
 
        sioFreeze(f, 1);
@@ -555,16 +668,15 @@ int SaveState(const char *file) {
        psxHwFreeze(f, 1);
        psxRcntFreeze(f, 1);
        mdecFreeze(f, 1);
+       new_dyna_freeze(f, 1);
 
-       gzclose(f);
-
-       new_dyna_after_save();
+       SaveFuncs.close(f);
 
        return 0;
 }
 
 int LoadState(const char *file) {
-       gzFile f;
+       void *f;
        GPUFreeze_t *gpufP;
        SPUFreeze_t *spufP;
        int Size;
@@ -572,15 +684,15 @@ int LoadState(const char *file) {
        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));
 
        if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
-               gzclose(f);
+               SaveFuncs.close(f);
                return -1;
        }
        Config.HLE = hle;
@@ -588,30 +700,31 @@ int LoadState(const char *file) {
        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;
 
-       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));
+       SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
        GPU_freeze(0, gpufP);
        free(gpufP);
        if (HW_GPU_STATUS == 0)
-               HW_GPU_STATUS = GPU_readStatus();
+               HW_GPU_STATUS = SWAP32(GPU_readStatus());
 
        // spu
-       gzread(f, &Size, 4);
+       SaveFuncs.read(f, &Size, 4);
        spufP = (SPUFreeze_t *)malloc(Size);
-       gzread(f, spufP, Size);
-       SPU_freeze(0, spufP);
+       SaveFuncs.read(f, spufP, Size);
+       SPU_freeze(0, spufP, psxRegs.cycle);
        free(spufP);
 
        sioFreeze(f, 0);
@@ -619,27 +732,27 @@ int LoadState(const char *file) {
        psxHwFreeze(f, 0);
        psxRcntFreeze(f, 0);
        mdecFreeze(f, 0);
+       new_dyna_freeze(f, 0);
 
-       gzclose(f);
-       new_dyna_restore();
+       SaveFuncs.close(f);
 
        return 0;
 }
 
 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;
@@ -653,10 +766,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);
 
@@ -669,10 +785,13 @@ 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();
@@ -681,7 +800,7 @@ int RecvPcsxInfo() {
        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
@@ -691,6 +810,7 @@ int RecvPcsxInfo() {
                        SysClose(); return -1;
                }
                psxCpu->Reset();
+               psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
        }
 
        return 0;