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