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