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