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