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