overwrite dynarec related code with upstream version
[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#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
112int 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
152static const unsigned int gpu_ctl_def[] = {
153 0x00000000, 0x01000000, 0x03000000, 0x04000000,
154 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
155};
156
157static const unsigned int gpu_data_def[] = {
158 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
159 0xe5001000, 0xe6000000,
160 0x02000000, 0x00000000, 0x01ff03ff,
161};
162
163static 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
174int 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 && !Config.SlowBoot) {
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
266int 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
313int 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 /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */
365 if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') {
366 size_t offset = 4;
367 size_t i, len = strlen(exename) - offset;
368 for (i = 0; i < len; i++)
369 exename[i] = exename[i + offset];
370 exename[i] = '\0';
371 }
372 } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
373 strcpy(exename, "PSX.EXE;1");
374 strcpy(CdromId, "SLUS99999");
375 } else
376 return -1; // SYSTEM.CNF and PSX.EXE not found
377
378 if (CdromId[0] == '\0') {
379 len = strlen(exename);
380 c = 0;
381 for (i = 0; i < len; ++i) {
382 if (exename[i] == ';' || c >= sizeof(CdromId) - 1)
383 break;
384 if (isalnum(exename[i]))
385 CdromId[c++] = exename[i];
386 }
387 }
388
389 if (CdromId[0] == '\0')
390 strcpy(CdromId, "SLUS99999");
391
392 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
393 if (
394 /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */
395 ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) ||
396 !strncmp(CdromId, "DTLS3035", 8) ||
397 !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL
398 !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID;
399 !strncmp(CdromId, "PBPX95008", 9)) // add more serials if they are discovered.
400 Config.PsxType = PSX_TYPE_PAL; // pal
401 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
402 }
403
404 if (CdromLabel[0] == ' ') {
405 strncpy(CdromLabel, CdromId, 9);
406 }
407 SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
408 SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
409 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
410
411 Apply_Hacks_Cdrom();
412
413 BuildPPFCache();
414
415 return 0;
416}
417
418static int PSXGetFileType(FILE *f) {
419 unsigned long current;
420 u8 mybuf[2048];
421 EXE_HEADER *exe_hdr;
422 FILHDR *coff_hdr;
423
424 current = ftell(f);
425 fseek(f, 0L, SEEK_SET);
426 if (fread(&mybuf, sizeof(mybuf), 1, f) != sizeof(mybuf))
427 goto io_fail;
428
429 fseek(f, current, SEEK_SET);
430
431 exe_hdr = (EXE_HEADER *)mybuf;
432 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
433 return PSX_EXE;
434
435 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
436 return CPE_EXE;
437
438 coff_hdr = (FILHDR *)mybuf;
439 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
440 return COFF_EXE;
441
442 return INVALID_EXE;
443
444io_fail:
445#ifndef NDEBUG
446 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
447#endif
448 return INVALID_EXE;
449}
450
451// temporary pandora workaround..
452// FIXME: remove
453size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
454{
455 void *tmp;
456 size_t ret = 0;
457
458 tmp = malloc(size * nmemb);
459 if (tmp) {
460 ret = fread(tmp, size, nmemb, stream);
461 memcpy(ptr, tmp, size * nmemb);
462 free(tmp);
463 }
464 return ret;
465}
466
467int Load(const char *ExePath) {
468 FILE *tmpFile;
469 EXE_HEADER tmpHead;
470 int type;
471 int retval = 0;
472 u8 opcode;
473 u32 section_address, section_size;
474 void *mem;
475
476 strcpy(CdromId, "SLUS99999");
477 strcpy(CdromLabel, "SLUS_999.99");
478
479 tmpFile = fopen(ExePath, "rb");
480 if (tmpFile == NULL) {
481 SysPrintf(_("Error opening file: %s.\n"), ExePath);
482 retval = -1;
483 } else {
484 type = PSXGetFileType(tmpFile);
485 switch (type) {
486 case PSX_EXE:
487 if (fread(&tmpHead, sizeof(EXE_HEADER), 1, tmpFile) != sizeof(EXE_HEADER))
488 goto fail_io;
489 section_address = SWAP32(tmpHead.t_addr);
490 section_size = SWAP32(tmpHead.t_size);
491 mem = PSXM(section_address);
492 if (mem != NULL) {
493 fseek(tmpFile, 0x800, SEEK_SET);
494 fread_to_ram(mem, section_size, 1, tmpFile);
495 psxCpu->Clear(section_address, section_size / 4);
496 }
497 psxRegs.pc = SWAP32(tmpHead.pc0);
498 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
499 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
500 if (psxRegs.GPR.n.sp == 0)
501 psxRegs.GPR.n.sp = 0x801fff00;
502 retval = 0;
503 break;
504 case CPE_EXE:
505 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
506 do {
507 if (fread(&opcode, sizeof(opcode), 1, tmpFile) != sizeof(opcode))
508 goto fail_io;
509 switch (opcode) {
510 case 1: /* Section loading */
511 if (fread(&section_address, sizeof(section_address), 1, tmpFile) != sizeof(section_address))
512 goto fail_io;
513 if (fread(&section_size, sizeof(section_size), 1, tmpFile) != sizeof(section_size))
514 goto fail_io;
515 section_address = SWAPu32(section_address);
516 section_size = SWAPu32(section_size);
517#ifdef EMU_LOG
518 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
519#endif
520 mem = PSXM(section_address);
521 if (mem != NULL) {
522 fread_to_ram(mem, section_size, 1, tmpFile);
523 psxCpu->Clear(section_address, section_size / 4);
524 }
525 break;
526 case 3: /* register loading (PC only?) */
527 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
528 if (fread(&psxRegs.pc, sizeof(psxRegs.pc), 1, tmpFile) != sizeof(psxRegs.pc))
529 goto fail_io;
530 psxRegs.pc = SWAPu32(psxRegs.pc);
531 break;
532 case 0: /* End of file */
533 break;
534 default:
535 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
536 retval = -1;
537 break;
538 }
539 } while (opcode != 0 && retval == 0);
540 break;
541 case COFF_EXE:
542 SysPrintf(_("COFF files not supported.\n"));
543 retval = -1;
544 break;
545 case INVALID_EXE:
546 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
547 SysPrintf(_("(did you forget -cdfile ?)\n"));
548 retval = -1;
549 break;
550 }
551 }
552
553 if (retval != 0) {
554 CdromId[0] = '\0';
555 CdromLabel[0] = '\0';
556 }
557
558 fclose(tmpFile);
559 return retval;
560
561fail_io:
562#ifndef NDEBUG
563 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
564#endif
565 fclose(tmpFile);
566 return -1;
567}
568
569// STATES
570
571static void *zlib_open(const char *name, const char *mode)
572{
573 return gzopen(name, mode);
574}
575
576static int zlib_read(void *file, void *buf, u32 len)
577{
578 return gzread(file, buf, len);
579}
580
581static int zlib_write(void *file, const void *buf, u32 len)
582{
583 return gzwrite(file, buf, len);
584}
585
586static long zlib_seek(void *file, long offs, int whence)
587{
588 return gzseek(file, offs, whence);
589}
590
591static void zlib_close(void *file)
592{
593 gzclose(file);
594}
595
596struct PcsxSaveFuncs SaveFuncs = {
597 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
598};
599
600static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
601
602// Savestate Versioning!
603// If you make changes to the savestate version, please increment the value below.
604static const u32 SaveVersion = 0x8b410006;
605
606int SaveState(const char *file) {
607 void *f;
608 GPUFreeze_t *gpufP;
609 SPUFreeze_t *spufP;
610 int Size;
611 unsigned char *pMem;
612
613 f = SaveFuncs.open(file, "wb");
614 if (f == NULL) return -1;
615
616 new_dyna_before_save();
617
618 SaveFuncs.write(f, (void *)PcsxHeader, 32);
619 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
620 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
621
622 pMem = (unsigned char *)malloc(128 * 96 * 3);
623 if (pMem == NULL) return -1;
624 GPU_getScreenPic(pMem);
625 SaveFuncs.write(f, pMem, 128 * 96 * 3);
626 free(pMem);
627
628 if (Config.HLE)
629 psxBiosFreeze(1);
630
631 SaveFuncs.write(f, psxM, 0x00200000);
632 SaveFuncs.write(f, psxR, 0x00080000);
633 SaveFuncs.write(f, psxH, 0x00010000);
634 // only partial save of psxRegisters to maintain savestate compat
635 SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
636
637 // gpu
638 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
639 gpufP->ulFreezeVersion = 1;
640 GPU_freeze(1, gpufP);
641 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
642 free(gpufP);
643
644 // spu
645 spufP = (SPUFreeze_t *) malloc(16);
646 SPU_freeze(2, spufP, psxRegs.cycle);
647 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
648 free(spufP);
649 spufP = (SPUFreeze_t *) malloc(Size);
650 SPU_freeze(1, spufP, psxRegs.cycle);
651 SaveFuncs.write(f, spufP, Size);
652 free(spufP);
653
654 sioFreeze(f, 1);
655 cdrFreeze(f, 1);
656 psxHwFreeze(f, 1);
657 psxRcntFreeze(f, 1);
658 mdecFreeze(f, 1);
659 new_dyna_freeze(f, 1);
660
661 SaveFuncs.close(f);
662
663 new_dyna_after_save();
664
665 return 0;
666}
667
668int LoadState(const char *file) {
669 void *f;
670 GPUFreeze_t *gpufP;
671 SPUFreeze_t *spufP;
672 int Size;
673 char header[32];
674 u32 version;
675 boolean hle;
676
677 f = SaveFuncs.open(file, "rb");
678 if (f == NULL) return -1;
679
680 SaveFuncs.read(f, header, sizeof(header));
681 SaveFuncs.read(f, &version, sizeof(u32));
682 SaveFuncs.read(f, &hle, sizeof(boolean));
683
684 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
685 SaveFuncs.close(f);
686 return -1;
687 }
688 Config.HLE = hle;
689
690 if (Config.HLE)
691 psxBiosInit();
692
693#if defined(LIGHTREC)
694 if (Config.Cpu != CPU_INTERPRETER)
695 psxCpu->Clear(0, UINT32_MAX); //clear all
696 else
697#endif
698 psxCpu->Reset();
699 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
700
701 SaveFuncs.read(f, psxM, 0x00200000);
702 SaveFuncs.read(f, psxR, 0x00080000);
703 SaveFuncs.read(f, psxH, 0x00010000);
704 SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
705 psxRegs.gteBusyCycle = psxRegs.cycle;
706
707 if (Config.HLE)
708 psxBiosFreeze(0);
709
710 // gpu
711 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
712 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
713 GPU_freeze(0, gpufP);
714 free(gpufP);
715 if (HW_GPU_STATUS == 0)
716 HW_GPU_STATUS = GPU_readStatus();
717
718 // spu
719 SaveFuncs.read(f, &Size, 4);
720 spufP = (SPUFreeze_t *)malloc(Size);
721 SaveFuncs.read(f, spufP, Size);
722 SPU_freeze(0, spufP, psxRegs.cycle);
723 free(spufP);
724
725 sioFreeze(f, 0);
726 cdrFreeze(f, 0);
727 psxHwFreeze(f, 0);
728 psxRcntFreeze(f, 0);
729 mdecFreeze(f, 0);
730 new_dyna_freeze(f, 0);
731
732 SaveFuncs.close(f);
733
734 return 0;
735}
736
737int CheckState(const char *file) {
738 void *f;
739 char header[32];
740 u32 version;
741 boolean hle;
742
743 f = SaveFuncs.open(file, "rb");
744 if (f == NULL) return -1;
745
746 SaveFuncs.read(f, header, sizeof(header));
747 SaveFuncs.read(f, &version, sizeof(u32));
748 SaveFuncs.read(f, &hle, sizeof(boolean));
749
750 SaveFuncs.close(f);
751
752 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
753 return -1;
754
755 return 0;
756}
757
758// NET Function Helpers
759
760int SendPcsxInfo() {
761 if (NET_recvData == NULL || NET_sendData == NULL)
762 return 0;
763
764 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
765 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
766 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
767 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
768 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
769 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
770
771 return 0;
772}
773
774int RecvPcsxInfo() {
775 int tmp;
776
777 if (NET_recvData == NULL || NET_sendData == NULL)
778 return 0;
779
780 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
781 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
782 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
783 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
784 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
785
786 SysUpdate();
787
788 tmp = Config.Cpu;
789 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
790 if (tmp != Config.Cpu) {
791 psxCpu->Shutdown();
792#ifndef DRC_DISABLE
793 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
794 else psxCpu = &psxRec;
795#else
796 psxCpu = &psxInt;
797#endif
798 if (psxCpu->Init() == -1) {
799 SysClose(); return -1;
800 }
801 psxCpu->Reset();
802 }
803
804 return 0;
805}
806
807// remove the leading and trailing spaces in a string
808void trim(char *str) {
809 int pos = 0;
810 char *dest = str;
811
812 // skip leading blanks
813 while (str[pos] <= ' ' && str[pos] > 0)
814 pos++;
815
816 while (str[pos]) {
817 *(dest++) = str[pos];
818 pos++;
819 }
820
821 *(dest--) = '\0'; // store the null
822
823 // remove trailing blanks
824 while (dest >= str && *dest <= ' ' && *dest > 0)
825 *(dest--) = '\0';
826}
827
828// lookup table for crc calculation
829static unsigned short crctab[256] = {
830 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
831 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
832 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
833 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
834 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
835 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
836 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
837 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
838 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
839 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
840 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
841 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
842 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
843 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
844 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
845 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
846 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
847 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
848 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
849 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
850 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
851 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
852 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
853 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
854 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
855 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
856 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
857 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
858 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
859};
860
861u16 calcCrc(u8 *d, int len) {
862 u16 crc = 0;
863 int i;
864
865 for (i = 0; i < len; i++) {
866 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
867 }
868
869 return ~crc;
870}