psxmem: Add mman wrapper for Win32 and use it for PCSX ReARmed libretro Win32
[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
211 sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename);
212 if (GetCdromFile(mdir, time, exename) == -1) {
213 sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
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
P
270
271 sscanf(filename, "cdrom:\\%256s", exename);
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];
315 int i, c;
316
317 FreePPFCache();
318
319 time[0] = itob(0);
320 time[1] = itob(2);
321 time[2] = itob(0x10);
322
323 READTRACK();
324
325 CdromLabel[0] = '\0';
326 CdromId[0] = '\0';
327
328 strncpy(CdromLabel, buf + 52, 32);
329
330 // skip head and sub, and go to the root directory record
331 dir = (struct iso_directory_record *)&buf[12 + 156];
332
333 mmssdd(dir->extent, (char *)time);
334
335 READDIR(mdir);
336
337 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
338 READTRACK();
339
305c8c93 340 sscanf(buf + 12, "BOOT = cdrom:\\%256s", exename);
ef79bbde 341 if (GetCdromFile(mdir, time, exename) == -1) {
305c8c93 342 sscanf(buf + 12, "BOOT = cdrom:%256s", exename);
ef79bbde
P
343 if (GetCdromFile(mdir, time, exename) == -1) {
344 char *ptr = strstr(buf + 12, "cdrom:"); // possibly the executable is in some subdir
345 if (ptr != NULL) {
346 ptr += 6;
347 while (*ptr == '\\' || *ptr == '/') ptr++;
348 strncpy(exename, ptr, 255);
349 exename[255] = '\0';
350 ptr = exename;
351 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
352 *ptr = '\0';
353 if (GetCdromFile(mdir, time, exename) == -1)
354 return -1; // main executable not found
355 } else
356 return -1;
357 }
358 }
359 } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
360 strcpy(exename, "PSX.EXE;1");
361 strcpy(CdromId, "SLUS99999");
362 } else
363 return -1; // SYSTEM.CNF and PSX.EXE not found
364
365 if (CdromId[0] == '\0') {
366 i = strlen(exename);
367 if (i >= 2) {
368 if (exename[i - 2] == ';') i-= 2;
369 c = 8; i--;
370 while (i >= 0 && c >= 0) {
371 if (isalnum(exename[i])) CdromId[c--] = exename[i];
372 i--;
373 }
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);
391
392 BuildPPFCache();
393
394 return 0;
395}
396
397static int PSXGetFileType(FILE *f) {
398 unsigned long current;
399 u8 mybuf[2048];
400 EXE_HEADER *exe_hdr;
401 FILHDR *coff_hdr;
402
403 current = ftell(f);
404 fseek(f, 0L, SEEK_SET);
405 fread(mybuf, 2048, 1, f);
406 fseek(f, current, SEEK_SET);
407
408 exe_hdr = (EXE_HEADER *)mybuf;
409 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
410 return PSX_EXE;
411
412 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
413 return CPE_EXE;
414
415 coff_hdr = (FILHDR *)mybuf;
416 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
417 return COFF_EXE;
418
419 return INVALID_EXE;
420}
421
96bef96f 422// temporary pandora workaround..
423// FIXME: remove
424size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
425{
426 void *tmp;
427 size_t ret = 0;
428
429 tmp = malloc(size * nmemb);
430 if (tmp) {
431 ret = fread(tmp, size, nmemb, stream);
432 memcpy(ptr, tmp, size * nmemb);
433 free(tmp);
434 }
435 return ret;
436}
437
ef79bbde
P
438int Load(const char *ExePath) {
439 FILE *tmpFile;
440 EXE_HEADER tmpHead;
441 int type;
442 int retval = 0;
443 u8 opcode;
444 u32 section_address, section_size;
ebe6ff2b 445 void *mem;
ef79bbde
P
446
447 strncpy(CdromId, "SLUS99999", 9);
448 strncpy(CdromLabel, "SLUS_999.99", 11);
449
450 tmpFile = fopen(ExePath, "rb");
451 if (tmpFile == NULL) {
452 SysPrintf(_("Error opening file: %s.\n"), ExePath);
453 retval = -1;
454 } else {
455 type = PSXGetFileType(tmpFile);
456 switch (type) {
457 case PSX_EXE:
458 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
ebe6ff2b 459 section_address = SWAP32(tmpHead.t_addr);
460 section_size = SWAP32(tmpHead.t_size);
461 mem = PSXM(section_address);
462 if (mem != NULL) {
463 fseek(tmpFile, 0x800, SEEK_SET);
96bef96f 464 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 465 psxCpu->Clear(section_address, section_size / 4);
466 }
ef79bbde
P
467 fclose(tmpFile);
468 psxRegs.pc = SWAP32(tmpHead.pc0);
469 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
470 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
471 if (psxRegs.GPR.n.sp == 0)
472 psxRegs.GPR.n.sp = 0x801fff00;
473 retval = 0;
474 break;
475 case CPE_EXE:
476 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
477 do {
478 fread(&opcode, 1, 1, tmpFile);
479 switch (opcode) {
480 case 1: /* Section loading */
481 fread(&section_address, 4, 1, tmpFile);
482 fread(&section_size, 4, 1, tmpFile);
483 section_address = SWAPu32(section_address);
484 section_size = SWAPu32(section_size);
485#ifdef EMU_LOG
486 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
487#endif
ebe6ff2b 488 mem = PSXM(section_address);
489 if (mem != NULL) {
96bef96f 490 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 491 psxCpu->Clear(section_address, section_size / 4);
492 }
ef79bbde
P
493 break;
494 case 3: /* register loading (PC only?) */
495 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
496 fread(&psxRegs.pc, 4, 1, tmpFile);
497 psxRegs.pc = SWAPu32(psxRegs.pc);
498 break;
499 case 0: /* End of file */
500 break;
501 default:
502 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
503 retval = -1;
504 break;
505 }
506 } while (opcode != 0 && retval == 0);
507 break;
508 case COFF_EXE:
509 SysPrintf(_("COFF files not supported.\n"));
510 retval = -1;
511 break;
512 case INVALID_EXE:
8f00f96c 513 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
514 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
515 retval = -1;
516 break;
517 }
518 }
519
520 if (retval != 0) {
521 CdromId[0] = '\0';
522 CdromLabel[0] = '\0';
523 }
524
525 return retval;
526}
527
528// STATES
529
496d88d4 530static void *zlib_open(const char *name, const char *mode)
531{
532 return gzopen(name, mode);
533}
534
535static int zlib_read(void *file, void *buf, u32 len)
536{
537 return gzread(file, buf, len);
538}
539
540static int zlib_write(void *file, const void *buf, u32 len)
541{
542 return gzwrite(file, buf, len);
543}
544
545static long zlib_seek(void *file, long offs, int whence)
546{
547 return gzseek(file, offs, whence);
548}
549
550static void zlib_close(void *file)
551{
552 gzclose(file);
553}
554
555struct PcsxSaveFuncs SaveFuncs = {
556 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
557};
558
ef79bbde
P
559static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
560
561// Savestate Versioning!
562// If you make changes to the savestate version, please increment the value below.
df656dde 563static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
564
565int SaveState(const char *file) {
496d88d4 566 void *f;
ef79bbde
P
567 GPUFreeze_t *gpufP;
568 SPUFreeze_t *spufP;
569 int Size;
570 unsigned char *pMem;
571
496d88d4 572 f = SaveFuncs.open(file, "wb");
ef79bbde
P
573 if (f == NULL) return -1;
574
52082bc1 575 new_dyna_save();
576
496d88d4 577 SaveFuncs.write(f, (void *)PcsxHeader, 32);
578 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
579 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
580
581 pMem = (unsigned char *)malloc(128 * 96 * 3);
582 if (pMem == NULL) return -1;
583 GPU_getScreenPic(pMem);
496d88d4 584 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
585 free(pMem);
586
587 if (Config.HLE)
588 psxBiosFreeze(1);
589
496d88d4 590 SaveFuncs.write(f, psxM, 0x00200000);
591 SaveFuncs.write(f, psxR, 0x00080000);
592 SaveFuncs.write(f, psxH, 0x00010000);
593 SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
594
595 // gpu
596 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
597 gpufP->ulFreezeVersion = 1;
598 GPU_freeze(1, gpufP);
496d88d4 599 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
600 free(gpufP);
601
602 // spu
603 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 604 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 605 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
606 free(spufP);
607 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 608 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 609 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
610 free(spufP);
611
612 sioFreeze(f, 1);
613 cdrFreeze(f, 1);
614 psxHwFreeze(f, 1);
615 psxRcntFreeze(f, 1);
616 mdecFreeze(f, 1);
617
496d88d4 618 SaveFuncs.close(f);
ef79bbde 619
5b8c000f 620 new_dyna_after_save();
621
ef79bbde
P
622 return 0;
623}
624
625int LoadState(const char *file) {
496d88d4 626 void *f;
ef79bbde
P
627 GPUFreeze_t *gpufP;
628 SPUFreeze_t *spufP;
629 int Size;
630 char header[32];
631 u32 version;
632 boolean hle;
633
496d88d4 634 f = SaveFuncs.open(file, "rb");
ef79bbde
P
635 if (f == NULL) return -1;
636
496d88d4 637 SaveFuncs.read(f, header, sizeof(header));
638 SaveFuncs.read(f, &version, sizeof(u32));
639 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 640
33f56da1 641 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 642 SaveFuncs.close(f);
ef79bbde
P
643 return -1;
644 }
33f56da1 645 Config.HLE = hle;
646
647 if (Config.HLE)
648 psxBiosInit();
ef79bbde
P
649
650 psxCpu->Reset();
496d88d4 651 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 652
496d88d4 653 SaveFuncs.read(f, psxM, 0x00200000);
654 SaveFuncs.read(f, psxR, 0x00080000);
655 SaveFuncs.read(f, psxH, 0x00010000);
656 SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
657
658 if (Config.HLE)
659 psxBiosFreeze(0);
660
661 // gpu
662 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 663 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
664 GPU_freeze(0, gpufP);
665 free(gpufP);
ddbaf678 666 if (HW_GPU_STATUS == 0)
667 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
668
669 // spu
496d88d4 670 SaveFuncs.read(f, &Size, 4);
ef79bbde 671 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 672 SaveFuncs.read(f, spufP, Size);
650adfd2 673 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
674 free(spufP);
675
676 sioFreeze(f, 0);
677 cdrFreeze(f, 0);
678 psxHwFreeze(f, 0);
679 psxRcntFreeze(f, 0);
680 mdecFreeze(f, 0);
681
496d88d4 682 SaveFuncs.close(f);
52082bc1 683 new_dyna_restore();
ef79bbde
P
684
685 return 0;
686}
687
688int CheckState(const char *file) {
496d88d4 689 void *f;
ef79bbde
P
690 char header[32];
691 u32 version;
692 boolean hle;
693
496d88d4 694 f = SaveFuncs.open(file, "rb");
ef79bbde
P
695 if (f == NULL) return -1;
696
496d88d4 697 SaveFuncs.read(f, header, sizeof(header));
698 SaveFuncs.read(f, &version, sizeof(u32));
699 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 700
496d88d4 701 SaveFuncs.close(f);
ef79bbde 702
33f56da1 703 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
704 return -1;
705
706 return 0;
707}
708
709// NET Function Helpers
710
711int SendPcsxInfo() {
712 if (NET_recvData == NULL || NET_sendData == NULL)
713 return 0;
714
715 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
716 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
717 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
718 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
719 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
720 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
721
722 return 0;
723}
724
725int RecvPcsxInfo() {
726 int tmp;
727
728 if (NET_recvData == NULL || NET_sendData == NULL)
729 return 0;
730
731 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
732 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
733 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
734 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
735 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
736
737 SysUpdate();
738
739 tmp = Config.Cpu;
740 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
741 if (tmp != Config.Cpu) {
742 psxCpu->Shutdown();
743#ifdef PSXREC
744 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
745 else psxCpu = &psxRec;
746#else
747 psxCpu = &psxInt;
748#endif
749 if (psxCpu->Init() == -1) {
750 SysClose(); return -1;
751 }
752 psxCpu->Reset();
753 }
754
755 return 0;
756}
757
758// remove the leading and trailing spaces in a string
759void trim(char *str) {
760 int pos = 0;
761 char *dest = str;
762
763 // skip leading blanks
764 while (str[pos] <= ' ' && str[pos] > 0)
765 pos++;
766
767 while (str[pos]) {
768 *(dest++) = str[pos];
769 pos++;
770 }
771
772 *(dest--) = '\0'; // store the null
773
774 // remove trailing blanks
775 while (dest >= str && *dest <= ' ' && *dest > 0)
776 *(dest--) = '\0';
777}
778
779// lookup table for crc calculation
780static unsigned short crctab[256] = {
781 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
782 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
783 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
784 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
785 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
786 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
787 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
788 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
789 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
790 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
791 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
792 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
793 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
794 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
795 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
796 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
797 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
798 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
799 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
800 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
801 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
802 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
803 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
804 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
805 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
806 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
807 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
808 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
809 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
810};
811
812u16 calcCrc(u8 *d, int len) {
813 u16 crc = 0;
814 int i;
815
816 for (i = 0; i < len; i++) {
817 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
818 }
819
820 return ~crc;
821}