drc/gte: add some stall handling
[pcsx_rearmed.git] / libpcsxcore / misc.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21 * Miscellaneous functions, including savestates and CD-ROM loading.
22 */
23
24 #include <stddef.h>
25 #include "misc.h"
26 #include "cdrom.h"
27 #include "mdec.h"
28 #include "gpu.h"
29 #include "ppf.h"
30 #include "database.h"
31 #include <zlib.h>
32
33 char CdromId[10] = "";
34 char CdromLabel[33] = "";
35
36 // PSX Executable types
37 #define PSX_EXE     1
38 #define CPE_EXE     2
39 #define COFF_EXE    3
40 #define INVALID_EXE 4
41
42 #define ISODCL(from, to) (to - from + 1)
43
44 struct iso_directory_record {
45         char length                     [ISODCL (1, 1)]; /* 711 */
46         char ext_attr_length            [ISODCL (2, 2)]; /* 711 */
47         char extent                     [ISODCL (3, 10)]; /* 733 */
48         char size                       [ISODCL (11, 18)]; /* 733 */
49         char date                       [ISODCL (19, 25)]; /* 7 by 711 */
50         char flags                      [ISODCL (26, 26)];
51         char file_unit_size             [ISODCL (27, 27)]; /* 711 */
52         char interleave                 [ISODCL (28, 28)]; /* 711 */
53         char volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
54         unsigned char name_len          [ISODCL (33, 33)]; /* 711 */
55         char name                       [1];
56 };
57
58 void mmssdd( char *b, char *p )
59 {
60         int m, s, d;
61 #if defined(__arm__)
62         unsigned char *u = (void *)b;
63         int block = (u[3] << 24) | (u[2] << 16) | (u[1] << 8) | u[0];
64 #elif defined(__BIGENDIAN__)
65         int block = (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | (b[3] << 24);
66 #else
67         int block = *((int*)b);
68 #endif
69
70         block += 150;
71         m = block / 4500;                       // minutes
72         block = block - m * 4500;       // minutes rest
73         s = block / 75;                         // seconds
74         d = block - s * 75;                     // seconds rest
75
76         m = ((m / 10) << 4) | m % 10;
77         s = ((s / 10) << 4) | s % 10;
78         d = ((d / 10) << 4) | d % 10;   
79
80         p[0] = m;
81         p[1] = s;
82         p[2] = d;
83 }
84
85 #define incTime() \
86         time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \
87         time[2]++; \
88         if(time[2] == 75) { \
89                 time[2] = 0; \
90                 time[1]++; \
91                 if (time[1] == 60) { \
92                         time[1] = 0; \
93                         time[0]++; \
94                 } \
95         } \
96         time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
97
98 #define READTRACK() \
99         if (CDR_readTrack(time) == -1) return -1; \
100         buf = (void *)CDR_getBuffer(); \
101         if (buf == NULL) return -1; \
102         else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
103
104 #define READDIR(_dir) \
105         READTRACK(); \
106         memcpy(_dir, buf + 12, 2048); \
107  \
108         incTime(); \
109         READTRACK(); \
110         memcpy(_dir + 2048, buf + 12, 2048);
111
112 int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
113         struct iso_directory_record *dir;
114         int retval = -1;
115         u8 ddir[4096];
116         u8 *buf;
117         int i;
118
119         // only try to scan if a filename is given
120         if (!strlen(filename)) return -1;
121
122         i = 0;
123         while (i < 4096) {
124                 dir = (struct iso_directory_record*) &mdir[i];
125                 if (dir->length[0] == 0) {
126                         return -1;
127                 }
128                 i += (u8)dir->length[0];
129
130                 if (dir->flags[0] & 0x2) { // it's a dir
131                         if (!strnicmp((char *)&dir->name[0], filename, dir->name_len[0])) {
132                                 if (filename[dir->name_len[0]] != '\\') continue;
133
134                                 filename += dir->name_len[0] + 1;
135
136                                 mmssdd(dir->extent, (char *)time);
137                                 READDIR(ddir);
138                                 i = 0;
139                                 mdir = ddir;
140                         }
141                 } else {
142                         if (!strnicmp((char *)&dir->name[0], filename, strlen(filename))) {
143                                 mmssdd(dir->extent, (char *)time);
144                                 retval = 0;
145                                 break;
146                         }
147                 }
148         }
149         return retval;
150 }
151
152 static const unsigned int gpu_ctl_def[] = {
153         0x00000000, 0x01000000, 0x03000000, 0x04000000,
154         0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
155 };
156
157 static const unsigned int gpu_data_def[] = {
158         0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
159         0xe5001000, 0xe6000000,
160         0x02000000, 0x00000000, 0x01ff03ff,
161 };
162
163 static void fake_bios_gpu_setup(void)
164 {
165         int i;
166
167         for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
168                 GPU_writeStatus(gpu_ctl_def[i]);
169
170         for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
171                 GPU_writeData(gpu_data_def[i]);
172 }
173
174 int LoadCdrom() {
175         EXE_HEADER tmpHead;
176         struct iso_directory_record *dir;
177         u8 time[4], *buf;
178         u8 mdir[4096];
179         char exename[256];
180
181         // not the best place to do it, but since BIOS boot logo killer
182         // is just below, do it here
183         fake_bios_gpu_setup();
184
185         if (!Config.HLE) {
186                 // skip BIOS logos
187                 psxRegs.pc = psxRegs.GPR.n.ra;
188                 return 0;
189         }
190
191         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
192
193         READTRACK();
194
195         // skip head and sub, and go to the root directory record
196         dir = (struct iso_directory_record*) &buf[12+156]; 
197
198         mmssdd(dir->extent, (char*)time);
199
200         READDIR(mdir);
201
202         // Load SYSTEM.CNF and scan for the main executable
203         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
204                 // if SYSTEM.CNF is missing, start an existing PSX.EXE
205                 if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
206
207                 READTRACK();
208         }
209         else {
210                 // read the SYSTEM.CNF
211                 READTRACK();
212
213                 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
214                 if (GetCdromFile(mdir, time, exename) == -1) {
215                         sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
216                         if (GetCdromFile(mdir, time, exename) == -1) {
217                                 char *ptr = strstr((char *)buf + 12, "cdrom:");
218                                 if (ptr != NULL) {
219                                         ptr += 6;
220                                         while (*ptr == '\\' || *ptr == '/') ptr++;
221                                         strncpy(exename, ptr, 255);
222                                         exename[255] = '\0';
223                                         ptr = exename;
224                                         while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
225                                         *ptr = '\0';
226                                         if (GetCdromFile(mdir, time, exename) == -1)
227                                                 return -1;
228                                 } else
229                                         return -1;
230                         }
231                 }
232
233                 // Read the EXE-Header
234                 READTRACK();
235         }
236
237         memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
238
239         psxRegs.pc = SWAP32(tmpHead.pc0);
240         psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
241         psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
242         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
243
244         tmpHead.t_size = SWAP32(tmpHead.t_size);
245         tmpHead.t_addr = SWAP32(tmpHead.t_addr);
246
247         psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
248         psxCpu->Reset();
249
250         // Read the rest of the main executable
251         while (tmpHead.t_size & ~2047) {
252                 void *ptr = (void *)PSXM(tmpHead.t_addr);
253
254                 incTime();
255                 READTRACK();
256
257                 if (ptr != NULL) memcpy(ptr, buf+12, 2048);
258
259                 tmpHead.t_size -= 2048;
260                 tmpHead.t_addr += 2048;
261         }
262
263         return 0;
264 }
265
266 int LoadCdromFile(const char *filename, EXE_HEADER *head) {
267         struct iso_directory_record *dir;
268         u8 time[4],*buf;
269         u8 mdir[4096];
270         char exename[256];
271         u32 size, addr;
272         void *mem;
273
274         sscanf(filename, "cdrom:\\%255s", exename);
275
276         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
277
278         READTRACK();
279
280         // skip head and sub, and go to the root directory record
281         dir = (struct iso_directory_record *)&buf[12 + 156]; 
282
283         mmssdd(dir->extent, (char*)time);
284
285         READDIR(mdir);
286
287         if (GetCdromFile(mdir, time, exename) == -1) return -1;
288
289         READTRACK();
290
291         memcpy(head, buf + 12, sizeof(EXE_HEADER));
292         size = head->t_size;
293         addr = head->t_addr;
294
295         psxCpu->Clear(addr, size / 4);
296         psxCpu->Reset();
297
298         while (size & ~2047) {
299                 incTime();
300                 READTRACK();
301
302                 mem = PSXM(addr);
303                 if (mem)
304                         memcpy(mem, buf + 12, 2048);
305
306                 size -= 2048;
307                 addr += 2048;
308         }
309
310         return 0;
311 }
312
313 int CheckCdrom() {
314         struct iso_directory_record *dir;
315         unsigned char time[4];
316         char *buf;
317         unsigned char mdir[4096];
318         char exename[256];
319         int i, len, c;
320
321         FreePPFCache();
322
323         time[0] = itob(0);
324         time[1] = itob(2);
325         time[2] = itob(0x10);
326
327         READTRACK();
328
329         memset(CdromLabel, 0, sizeof(CdromLabel));
330         memset(CdromId, 0, sizeof(CdromId));
331         memset(exename, 0, sizeof(exename));
332
333         strncpy(CdromLabel, buf + 52, 32);
334
335         // skip head and sub, and go to the root directory record
336         dir = (struct iso_directory_record *)&buf[12 + 156]; 
337
338         mmssdd(dir->extent, (char *)time);
339
340         READDIR(mdir);
341
342         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
343                 READTRACK();
344
345                 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
346                 if (GetCdromFile(mdir, time, exename) == -1) {
347                         sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
348                         if (GetCdromFile(mdir, time, exename) == -1) {
349                                 char *ptr = strstr(buf + 12, "cdrom:");                 // possibly the executable is in some subdir
350                                 if (ptr != NULL) {
351                                         ptr += 6;
352                                         while (*ptr == '\\' || *ptr == '/') ptr++;
353                                         strncpy(exename, ptr, 255);
354                                         exename[255] = '\0';
355                                         ptr = exename;
356                                         while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
357                                         *ptr = '\0';
358                                         if (GetCdromFile(mdir, time, exename) == -1)
359                                                 return -1;              // main executable not found
360                                 } else
361                                         return -1;
362                         }
363                 }
364         } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
365                 strcpy(exename, "PSX.EXE;1");
366                 strcpy(CdromId, "SLUS99999");
367         } else
368                 return -1;              // SYSTEM.CNF and PSX.EXE not found
369
370         if (CdromId[0] == '\0') {
371                 len = strlen(exename);
372                 c = 0;
373                 for (i = 0; i < len; ++i) {
374                         if (exename[i] == ';' || c >= sizeof(CdromId) - 1)
375                                 break;
376                         if (isalnum(exename[i]))
377                                 CdromId[c++] = exename[i];
378                 }
379         }
380
381         if (CdromId[0] == '\0')
382                 strcpy(CdromId, "SLUS99999");
383
384         if (Config.PsxAuto) { // autodetect system (pal or ntsc)
385                 if (
386                         /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */
387                         ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) ||
388                         !strncmp(CdromId, "DTLS3035", 8) ||
389                         !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL
390                         !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID;
391                         !strncmp(CdromId, "PBPX95008", 9))   // add more serials if they are discovered.
392                         Config.PsxType = PSX_TYPE_PAL; // pal
393                 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
394         }
395
396         if (CdromLabel[0] == ' ') {
397                 strncpy(CdromLabel, CdromId, 9);
398         }
399         SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
400         SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
401         SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
402         
403         Apply_Hacks_Cdrom();
404
405         BuildPPFCache();
406
407         return 0;
408 }
409
410 static int PSXGetFileType(FILE *f) {
411         unsigned long current;
412         u8 mybuf[2048];
413         EXE_HEADER *exe_hdr;
414         FILHDR *coff_hdr;
415
416         current = ftell(f);
417         fseek(f, 0L, SEEK_SET);
418         fread(mybuf, 2048, 1, f);
419         fseek(f, current, SEEK_SET);
420
421         exe_hdr = (EXE_HEADER *)mybuf;
422         if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
423                 return PSX_EXE;
424
425         if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
426                 return CPE_EXE;
427
428         coff_hdr = (FILHDR *)mybuf;
429         if (SWAPu16(coff_hdr->f_magic) == 0x0162)
430                 return COFF_EXE;
431
432         return INVALID_EXE;
433 }
434
435 // temporary pandora workaround..
436 // FIXME: remove
437 size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
438 {
439         void *tmp;
440         size_t ret = 0;
441         
442         tmp = malloc(size * nmemb);
443         if (tmp) {
444                 ret = fread(tmp, size, nmemb, stream);
445                 memcpy(ptr, tmp, size * nmemb);
446                 free(tmp);
447         }
448         return ret;
449 }
450
451 int Load(const char *ExePath) {
452         FILE *tmpFile;
453         EXE_HEADER tmpHead;
454         int type;
455         int retval = 0;
456         u8 opcode;
457         u32 section_address, section_size;
458         void *mem;
459
460         strncpy(CdromId, "SLUS99999", 9);
461         strncpy(CdromLabel, "SLUS_999.99", 11);
462
463         tmpFile = fopen(ExePath, "rb");
464         if (tmpFile == NULL) {
465                 SysPrintf(_("Error opening file: %s.\n"), ExePath);
466                 retval = -1;
467         } else {
468                 type = PSXGetFileType(tmpFile);
469                 switch (type) {
470                         case PSX_EXE:
471                                 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
472                                 section_address = SWAP32(tmpHead.t_addr);
473                                 section_size = SWAP32(tmpHead.t_size);
474                                 mem = PSXM(section_address);
475                                 if (mem != NULL) {
476                                         fseek(tmpFile, 0x800, SEEK_SET);                
477                                         fread_to_ram(mem, section_size, 1, tmpFile);
478                                         psxCpu->Clear(section_address, section_size / 4);
479                                 }
480                                 fclose(tmpFile);
481                                 psxRegs.pc = SWAP32(tmpHead.pc0);
482                                 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
483                                 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
484                                 if (psxRegs.GPR.n.sp == 0)
485                                         psxRegs.GPR.n.sp = 0x801fff00;
486                                 retval = 0;
487                                 break;
488                         case CPE_EXE:
489                                 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
490                                 do {
491                                         fread(&opcode, 1, 1, tmpFile);
492                                         switch (opcode) {
493                                                 case 1: /* Section loading */
494                                                         fread(&section_address, 4, 1, tmpFile);
495                                                         fread(&section_size, 4, 1, tmpFile);
496                                                         section_address = SWAPu32(section_address);
497                                                         section_size = SWAPu32(section_size);
498 #ifdef EMU_LOG
499                                                         EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
500 #endif
501                                                         mem = PSXM(section_address);
502                                                         if (mem != NULL) {
503                                                                 fread_to_ram(mem, section_size, 1, tmpFile);
504                                                                 psxCpu->Clear(section_address, section_size / 4);
505                                                         }
506                                                         break;
507                                                 case 3: /* register loading (PC only?) */
508                                                         fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
509                                                         fread(&psxRegs.pc, 4, 1, tmpFile);
510                                                         psxRegs.pc = SWAPu32(psxRegs.pc);
511                                                         break;
512                                                 case 0: /* End of file */
513                                                         break;
514                                                 default:
515                                                         SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
516                                                         retval = -1;
517                                                         break;
518                                         }
519                                 } while (opcode != 0 && retval == 0);
520                                 break;
521                         case COFF_EXE:
522                                 SysPrintf(_("COFF files not supported.\n"));
523                                 retval = -1;
524                                 break;
525                         case INVALID_EXE:
526                                 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
527                                 SysPrintf(_("(did you forget -cdfile ?)\n"));
528                                 retval = -1;
529                                 break;
530                 }
531         }
532
533         if (retval != 0) {
534                 CdromId[0] = '\0';
535                 CdromLabel[0] = '\0';
536         }
537
538         return retval;
539 }
540
541 // STATES
542
543 static void *zlib_open(const char *name, const char *mode)
544 {
545         return gzopen(name, mode);
546 }
547
548 static int zlib_read(void *file, void *buf, u32 len)
549 {
550         return gzread(file, buf, len);
551 }
552
553 static int zlib_write(void *file, const void *buf, u32 len)
554 {
555         return gzwrite(file, buf, len);
556 }
557
558 static long zlib_seek(void *file, long offs, int whence)
559 {
560         return gzseek(file, offs, whence);
561 }
562
563 static void zlib_close(void *file)
564 {
565         gzclose(file);
566 }
567
568 struct PcsxSaveFuncs SaveFuncs = {
569         zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
570 };
571
572 static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
573
574 // Savestate Versioning!
575 // If you make changes to the savestate version, please increment the value below.
576 static const u32 SaveVersion = 0x8b410006;
577
578 int SaveState(const char *file) {
579         void *f;
580         GPUFreeze_t *gpufP;
581         SPUFreeze_t *spufP;
582         int Size;
583         unsigned char *pMem;
584
585         f = SaveFuncs.open(file, "wb");
586         if (f == NULL) return -1;
587
588         new_dyna_before_save();
589
590         SaveFuncs.write(f, (void *)PcsxHeader, 32);
591         SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
592         SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
593
594         pMem = (unsigned char *)malloc(128 * 96 * 3);
595         if (pMem == NULL) return -1;
596         GPU_getScreenPic(pMem);
597         SaveFuncs.write(f, pMem, 128 * 96 * 3);
598         free(pMem);
599
600         if (Config.HLE)
601                 psxBiosFreeze(1);
602
603         SaveFuncs.write(f, psxM, 0x00200000);
604         SaveFuncs.write(f, psxR, 0x00080000);
605         SaveFuncs.write(f, psxH, 0x00010000);
606         // only partial save of psxRegisters to maintain savestate compat
607         SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
608
609         // gpu
610         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
611         gpufP->ulFreezeVersion = 1;
612         GPU_freeze(1, gpufP);
613         SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
614         free(gpufP);
615
616         // spu
617         spufP = (SPUFreeze_t *) malloc(16);
618         SPU_freeze(2, spufP, psxRegs.cycle);
619         Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
620         free(spufP);
621         spufP = (SPUFreeze_t *) malloc(Size);
622         SPU_freeze(1, spufP, psxRegs.cycle);
623         SaveFuncs.write(f, spufP, Size);
624         free(spufP);
625
626         sioFreeze(f, 1);
627         cdrFreeze(f, 1);
628         psxHwFreeze(f, 1);
629         psxRcntFreeze(f, 1);
630         mdecFreeze(f, 1);
631         new_dyna_freeze(f, 1);
632
633         SaveFuncs.close(f);
634
635         new_dyna_after_save();
636
637         return 0;
638 }
639
640 int LoadState(const char *file) {
641         void *f;
642         GPUFreeze_t *gpufP;
643         SPUFreeze_t *spufP;
644         int Size;
645         char header[32];
646         u32 version;
647         boolean hle;
648
649         f = SaveFuncs.open(file, "rb");
650         if (f == NULL) return -1;
651
652         SaveFuncs.read(f, header, sizeof(header));
653         SaveFuncs.read(f, &version, sizeof(u32));
654         SaveFuncs.read(f, &hle, sizeof(boolean));
655
656         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
657                 SaveFuncs.close(f);
658                 return -1;
659         }
660         Config.HLE = hle;
661
662         if (Config.HLE)
663                 psxBiosInit();
664
665         psxCpu->Reset();
666         SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
667
668         SaveFuncs.read(f, psxM, 0x00200000);
669         SaveFuncs.read(f, psxR, 0x00080000);
670         SaveFuncs.read(f, psxH, 0x00010000);
671         SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
672         psxRegs.gteBusyCycle = psxRegs.cycle;
673
674         if (Config.HLE)
675                 psxBiosFreeze(0);
676
677         // gpu
678         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
679         SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
680         GPU_freeze(0, gpufP);
681         free(gpufP);
682         if (HW_GPU_STATUS == 0)
683                 HW_GPU_STATUS = GPU_readStatus();
684
685         // spu
686         SaveFuncs.read(f, &Size, 4);
687         spufP = (SPUFreeze_t *)malloc(Size);
688         SaveFuncs.read(f, spufP, Size);
689         SPU_freeze(0, spufP, psxRegs.cycle);
690         free(spufP);
691
692         sioFreeze(f, 0);
693         cdrFreeze(f, 0);
694         psxHwFreeze(f, 0);
695         psxRcntFreeze(f, 0);
696         mdecFreeze(f, 0);
697         new_dyna_freeze(f, 0);
698
699         SaveFuncs.close(f);
700
701         return 0;
702 }
703
704 int CheckState(const char *file) {
705         void *f;
706         char header[32];
707         u32 version;
708         boolean hle;
709
710         f = SaveFuncs.open(file, "rb");
711         if (f == NULL) return -1;
712
713         SaveFuncs.read(f, header, sizeof(header));
714         SaveFuncs.read(f, &version, sizeof(u32));
715         SaveFuncs.read(f, &hle, sizeof(boolean));
716
717         SaveFuncs.close(f);
718
719         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
720                 return -1;
721
722         return 0;
723 }
724
725 // NET Function Helpers
726
727 int SendPcsxInfo() {
728         if (NET_recvData == NULL || NET_sendData == NULL)
729                 return 0;
730
731         NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
732         NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
733         NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
734         NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
735         NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
736         NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
737
738         return 0;
739 }
740
741 int RecvPcsxInfo() {
742         int tmp;
743
744         if (NET_recvData == NULL || NET_sendData == NULL)
745                 return 0;
746
747         NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
748         NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
749         NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
750         NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
751         NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
752
753         SysUpdate();
754
755         tmp = Config.Cpu;
756         NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
757         if (tmp != Config.Cpu) {
758                 psxCpu->Shutdown();
759 #ifndef DRC_DISABLE
760                 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
761                 else psxCpu = &psxRec;
762 #else
763                 psxCpu = &psxInt;
764 #endif
765                 if (psxCpu->Init() == -1) {
766                         SysClose(); return -1;
767                 }
768                 psxCpu->Reset();
769         }
770
771         return 0;
772 }
773
774 // remove the leading and trailing spaces in a string
775 void trim(char *str) {
776         int pos = 0;
777         char *dest = str;
778
779         // skip leading blanks
780         while (str[pos] <= ' ' && str[pos] > 0)
781                 pos++;
782
783         while (str[pos]) {
784                 *(dest++) = str[pos];
785                 pos++;
786         }
787
788         *(dest--) = '\0'; // store the null
789
790         // remove trailing blanks
791         while (dest >= str && *dest <= ' ' && *dest > 0)
792                 *(dest--) = '\0';
793 }
794
795 // lookup table for crc calculation
796 static unsigned short crctab[256] = {
797         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
798         0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
799         0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
800         0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
801         0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
802         0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
803         0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
804         0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
805         0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
806         0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
807         0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
808         0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
809         0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
810         0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
811         0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
812         0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
813         0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
814         0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
815         0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
816         0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
817         0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
818         0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
819         0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
820         0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
821         0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
822         0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
823         0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
824         0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
825         0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
826 };
827
828 u16 calcCrc(u8 *d, int len) {
829         u16 crc = 0;
830         int i;
831
832         for (i = 0; i < len; i++) {
833                 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
834         }
835
836         return ~crc;
837 }