gpu_neon: fix another abi violation
[pcsx_rearmed.git] / libpcsxcore / misc.c
CommitLineData
ef79bbde
P
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
81dbbf4c 24#include <stddef.h>
ef79bbde
P
25#include "misc.h"
26#include "cdrom.h"
27#include "mdec.h"
ddbaf678 28#include "gpu.h"
ef79bbde 29#include "ppf.h"
eedfe806 30#include "database.h"
496d88d4 31#include <zlib.h>
ef79bbde
P
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;
96c6ec70 61 int block = SWAP32(*((uint32_t*) b));
ef79bbde
P
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; \
305c8c93 93 buf = (void *)CDR_getBuffer(); \
94 if (buf == NULL) return -1; \
95 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
ef79bbde
P
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
305c8c93 105int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
ef79bbde 106 struct iso_directory_record *dir;
5be6eaeb 107 int retval = -1;
305c8c93 108 u8 ddir[4096];
ef79bbde
P
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 }
1c2c2bfb 121 i += (u8)dir->length[0];
ef79bbde
P
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);
5be6eaeb 137 retval = 0;
ef79bbde
P
138 break;
139 }
140 }
141 }
5be6eaeb 142 return retval;
ef79bbde
P
143}
144
f3a78e7e 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
ef79bbde
P
167int LoadCdrom() {
168 EXE_HEADER tmpHead;
169 struct iso_directory_record *dir;
170 u8 time[4], *buf;
171 u8 mdir[4096];
305c8c93 172 char exename[256];
ef79bbde 173
f3a78e7e 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
ef79bbde 178 if (!Config.HLE) {
f3a78e7e 179 // skip BIOS logos
ef79bbde
P
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
9a9bcd78 206 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 207 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 208 sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde 209 if (GetCdromFile(mdir, time, exename) == -1) {
305c8c93 210 char *ptr = strstr((char *)buf + 12, "cdrom:");
ef79bbde
P
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
ebe6ff2b 240 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
7bbabe80 241 psxCpu->Reset();
ebe6ff2b 242
ef79bbde 243 // Read the rest of the main executable
ebe6ff2b 244 while (tmpHead.t_size & ~2047) {
ef79bbde
P
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;
305c8c93 262 u8 mdir[4096];
263 char exename[256];
ef79bbde 264 u32 size, addr;
305c8c93 265 void *mem;
ef79bbde 266
9a9bcd78 267 sscanf(filename, "cdrom:\\%255s", exename);
ef79bbde
P
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
ebe6ff2b 288 psxCpu->Clear(addr, size / 4);
7bbabe80 289 psxCpu->Reset();
ebe6ff2b 290
291 while (size & ~2047) {
ef79bbde
P
292 incTime();
293 READTRACK();
294
305c8c93 295 mem = PSXM(addr);
296 if (mem)
297 memcpy(mem, buf + 12, 2048);
ef79bbde
P
298
299 size -= 2048;
300 addr += 2048;
301 }
302
303 return 0;
304}
305
306int CheckCdrom() {
307 struct iso_directory_record *dir;
305c8c93 308 unsigned char time[4];
309 char *buf;
ef79bbde
P
310 unsigned char mdir[4096];
311 char exename[256];
e06ee7f4 312 int i, len, c;
ef79bbde
P
313
314 FreePPFCache();
315
316 time[0] = itob(0);
317 time[1] = itob(2);
318 time[2] = itob(0x10);
319
320 READTRACK();
321
e06ee7f4 322 memset(CdromLabel, 0, sizeof(CdromLabel));
323 memset(CdromId, 0, sizeof(CdromId));
324 memset(exename, 0, sizeof(exename));
ef79bbde
P
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
9a9bcd78 338 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 339 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 340 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde
P
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') {
e06ee7f4 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];
ef79bbde
P
371 }
372 }
373
0e2e3f49 374 if (CdromId[0] == '\0')
375 strcpy(CdromId, "SLUS99999");
376
ef79bbde 377 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
40337130 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.
ef79bbde
P
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);
e06ee7f4 394 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
eedfe806 395
396 Apply_Hacks_Cdrom();
ef79bbde
P
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
96bef96f 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
ef79bbde
P
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;
ebe6ff2b 451 void *mem;
ef79bbde
P
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);
ebe6ff2b 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);
96bef96f 470 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 471 psxCpu->Clear(section_address, section_size / 4);
472 }
ef79bbde
P
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
ebe6ff2b 494 mem = PSXM(section_address);
495 if (mem != NULL) {
96bef96f 496 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 497 psxCpu->Clear(section_address, section_size / 4);
498 }
ef79bbde
P
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:
8f00f96c 519 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
520 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
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
496d88d4 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
ef79bbde
P
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.
df656dde 569static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
570
571int SaveState(const char *file) {
496d88d4 572 void *f;
ef79bbde
P
573 GPUFreeze_t *gpufP;
574 SPUFreeze_t *spufP;
575 int Size;
576 unsigned char *pMem;
577
496d88d4 578 f = SaveFuncs.open(file, "wb");
ef79bbde
P
579 if (f == NULL) return -1;
580
03f55e6b 581 new_dyna_before_save();
52082bc1 582
496d88d4 583 SaveFuncs.write(f, (void *)PcsxHeader, 32);
584 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
585 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
586
587 pMem = (unsigned char *)malloc(128 * 96 * 3);
588 if (pMem == NULL) return -1;
589 GPU_getScreenPic(pMem);
496d88d4 590 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
591 free(pMem);
592
593 if (Config.HLE)
594 psxBiosFreeze(1);
595
496d88d4 596 SaveFuncs.write(f, psxM, 0x00200000);
597 SaveFuncs.write(f, psxR, 0x00080000);
598 SaveFuncs.write(f, psxH, 0x00010000);
81dbbf4c 599 // only partial save of psxRegisters to maintain savestate compat
600 SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
ef79bbde
P
601
602 // gpu
603 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
604 gpufP->ulFreezeVersion = 1;
605 GPU_freeze(1, gpufP);
496d88d4 606 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
607 free(gpufP);
608
609 // spu
610 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 611 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 612 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
613 free(spufP);
614 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 615 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 616 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
617 free(spufP);
618
619 sioFreeze(f, 1);
620 cdrFreeze(f, 1);
621 psxHwFreeze(f, 1);
622 psxRcntFreeze(f, 1);
623 mdecFreeze(f, 1);
03f55e6b 624 new_dyna_freeze(f, 1);
ef79bbde 625
496d88d4 626 SaveFuncs.close(f);
ef79bbde 627
5b8c000f 628 new_dyna_after_save();
629
ef79bbde
P
630 return 0;
631}
632
633int LoadState(const char *file) {
496d88d4 634 void *f;
ef79bbde
P
635 GPUFreeze_t *gpufP;
636 SPUFreeze_t *spufP;
637 int Size;
638 char header[32];
639 u32 version;
640 boolean hle;
641
496d88d4 642 f = SaveFuncs.open(file, "rb");
ef79bbde
P
643 if (f == NULL) return -1;
644
496d88d4 645 SaveFuncs.read(f, header, sizeof(header));
646 SaveFuncs.read(f, &version, sizeof(u32));
647 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 648
33f56da1 649 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 650 SaveFuncs.close(f);
ef79bbde
P
651 return -1;
652 }
33f56da1 653 Config.HLE = hle;
654
655 if (Config.HLE)
656 psxBiosInit();
ef79bbde
P
657
658 psxCpu->Reset();
496d88d4 659 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 660
496d88d4 661 SaveFuncs.read(f, psxM, 0x00200000);
662 SaveFuncs.read(f, psxR, 0x00080000);
663 SaveFuncs.read(f, psxH, 0x00010000);
81dbbf4c 664 SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
665 psxRegs.gteBusyCycle = psxRegs.cycle;
ef79bbde
P
666
667 if (Config.HLE)
668 psxBiosFreeze(0);
669
670 // gpu
671 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 672 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
673 GPU_freeze(0, gpufP);
674 free(gpufP);
ddbaf678 675 if (HW_GPU_STATUS == 0)
086adfff 676 HW_GPU_STATUS = SWAP32(GPU_readStatus());
ef79bbde
P
677
678 // spu
496d88d4 679 SaveFuncs.read(f, &Size, 4);
ef79bbde 680 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 681 SaveFuncs.read(f, spufP, Size);
650adfd2 682 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
683 free(spufP);
684
685 sioFreeze(f, 0);
686 cdrFreeze(f, 0);
687 psxHwFreeze(f, 0);
688 psxRcntFreeze(f, 0);
689 mdecFreeze(f, 0);
03f55e6b 690 new_dyna_freeze(f, 0);
ef79bbde 691
496d88d4 692 SaveFuncs.close(f);
ef79bbde
P
693
694 return 0;
695}
696
697int CheckState(const char *file) {
496d88d4 698 void *f;
ef79bbde
P
699 char header[32];
700 u32 version;
701 boolean hle;
702
496d88d4 703 f = SaveFuncs.open(file, "rb");
ef79bbde
P
704 if (f == NULL) return -1;
705
496d88d4 706 SaveFuncs.read(f, header, sizeof(header));
707 SaveFuncs.read(f, &version, sizeof(u32));
708 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 709
496d88d4 710 SaveFuncs.close(f);
ef79bbde 711
33f56da1 712 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
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();
41e82ad4 752#ifndef DRC_DISABLE
ef79bbde
P
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}