psx_gpu: fix interlace mode
[pcsx_rearmed.git] / libpcsxcore / misc.c
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
30 char CdromId[10] = "";
31 char 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
41 struct 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
55 void mmssdd( char *b, char *p )
56 {
57         int m, s, d;
58 #if defined(__arm__)
59         int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
60 #elif defined(__BIGENDIAN__)
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
107 int 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
145 static const unsigned int gpu_ctl_def[] = {
146         0x00000000, 0x01000000, 0x03000000, 0x04000000,
147         0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
148 };
149
150 static const unsigned int gpu_data_def[] = {
151         0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
152         0xe5001000, 0xe6000000,
153         0x02000000, 0x00000000, 0x01ff03ff,
154 };
155
156 static 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
167 int 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
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
178         if (!Config.HLE) {
179                 // skip BIOS logos
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
240         psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
241
242         // Read the rest of the main executable
243         while (tmpHead.t_size & ~2047) {
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
258 int 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
285         psxCpu->Clear(addr, size / 4);
286
287         while (size & ~2047) {
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
300 int 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
367         if (CdromId[0] == '\0')
368                 strcpy(CdromId, "SLUS99999");
369
370         if (Config.PsxAuto) { // autodetect system (pal or ntsc)
371                 if (CdromId[2] == 'e' || CdromId[2] == 'E')
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
387 static 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
412 int Load(const char *ExePath) {
413         FILE *tmpFile;
414         EXE_HEADER tmpHead;
415         int type;
416         int retval = 0;
417         u8 opcode;
418         u32 section_address, section_size;
419         void *mem;
420
421         strncpy(CdromId, "SLUS99999", 9);
422         strncpy(CdromLabel, "SLUS_999.99", 11);
423
424         tmpFile = fopen(ExePath, "rb");
425         if (tmpFile == NULL) {
426                 SysPrintf(_("Error opening file: %s.\n"), ExePath);
427                 retval = -1;
428         } else {
429                 type = PSXGetFileType(tmpFile);
430                 switch (type) {
431                         case PSX_EXE:
432                                 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
433                                 section_address = SWAP32(tmpHead.t_addr);
434                                 section_size = SWAP32(tmpHead.t_size);
435                                 mem = PSXM(section_address);
436                                 if (mem != NULL) {
437                                         fseek(tmpFile, 0x800, SEEK_SET);                
438                                         fread(mem, section_size, 1, tmpFile);
439                                         psxCpu->Clear(section_address, section_size / 4);
440                                 }
441                                 fclose(tmpFile);
442                                 psxRegs.pc = SWAP32(tmpHead.pc0);
443                                 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
444                                 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
445                                 if (psxRegs.GPR.n.sp == 0)
446                                         psxRegs.GPR.n.sp = 0x801fff00;
447                                 retval = 0;
448                                 break;
449                         case CPE_EXE:
450                                 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
451                                 do {
452                                         fread(&opcode, 1, 1, tmpFile);
453                                         switch (opcode) {
454                                                 case 1: /* Section loading */
455                                                         fread(&section_address, 4, 1, tmpFile);
456                                                         fread(&section_size, 4, 1, tmpFile);
457                                                         section_address = SWAPu32(section_address);
458                                                         section_size = SWAPu32(section_size);
459 #ifdef EMU_LOG
460                                                         EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
461 #endif
462                                                         mem = PSXM(section_address);
463                                                         if (mem != NULL) {
464                                                                 fread(mem, section_size, 1, tmpFile);
465                                                                 psxCpu->Clear(section_address, section_size / 4);
466                                                         }
467                                                         break;
468                                                 case 3: /* register loading (PC only?) */
469                                                         fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
470                                                         fread(&psxRegs.pc, 4, 1, tmpFile);
471                                                         psxRegs.pc = SWAPu32(psxRegs.pc);
472                                                         break;
473                                                 case 0: /* End of file */
474                                                         break;
475                                                 default:
476                                                         SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
477                                                         retval = -1;
478                                                         break;
479                                         }
480                                 } while (opcode != 0 && retval == 0);
481                                 break;
482                         case COFF_EXE:
483                                 SysPrintf(_("COFF files not supported.\n"));
484                                 retval = -1;
485                                 break;
486                         case INVALID_EXE:
487                                 SysPrintf(_("This file does not appear to be a valid PSX file.\n"));
488                                 retval = -1;
489                                 break;
490                 }
491         }
492
493         if (retval != 0) {
494                 CdromId[0] = '\0';
495                 CdromLabel[0] = '\0';
496         }
497
498         return retval;
499 }
500
501 // STATES
502
503 static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
504
505 // Savestate Versioning!
506 // If you make changes to the savestate version, please increment the value below.
507 static const u32 SaveVersion = 0x8b410006;
508
509 int SaveState(const char *file) {
510         gzFile f;
511         GPUFreeze_t *gpufP;
512         SPUFreeze_t *spufP;
513         int Size;
514         unsigned char *pMem;
515
516         f = gzopen(file, "wb");
517         if (f == NULL) return -1;
518
519         new_dyna_save();
520
521         gzwrite(f, (void *)PcsxHeader, 32);
522         gzwrite(f, (void *)&SaveVersion, sizeof(u32));
523         gzwrite(f, (void *)&Config.HLE, sizeof(boolean));
524
525         pMem = (unsigned char *)malloc(128 * 96 * 3);
526         if (pMem == NULL) return -1;
527         GPU_getScreenPic(pMem);
528         gzwrite(f, pMem, 128 * 96 * 3);
529         free(pMem);
530
531         if (Config.HLE)
532                 psxBiosFreeze(1);
533
534         gzwrite(f, psxM, 0x00200000);
535         gzwrite(f, psxR, 0x00080000);
536         gzwrite(f, psxH, 0x00010000);
537         gzwrite(f, (void *)&psxRegs, sizeof(psxRegs));
538
539         // gpu
540         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
541         gpufP->ulFreezeVersion = 1;
542         GPU_freeze(1, gpufP);
543         gzwrite(f, gpufP, sizeof(GPUFreeze_t));
544         free(gpufP);
545
546         // spu
547         spufP = (SPUFreeze_t *) malloc(16);
548         SPU_freeze(2, spufP);
549         Size = spufP->Size; gzwrite(f, &Size, 4);
550         free(spufP);
551         spufP = (SPUFreeze_t *) malloc(Size);
552         SPU_freeze(1, spufP);
553         gzwrite(f, spufP, Size);
554         free(spufP);
555
556         sioFreeze(f, 1);
557         cdrFreeze(f, 1);
558         psxHwFreeze(f, 1);
559         psxRcntFreeze(f, 1);
560         mdecFreeze(f, 1);
561
562         gzclose(f);
563
564         new_dyna_after_save();
565
566         return 0;
567 }
568
569 int LoadState(const char *file) {
570         gzFile f;
571         GPUFreeze_t *gpufP;
572         SPUFreeze_t *spufP;
573         int Size;
574         char header[32];
575         u32 version;
576         boolean hle;
577
578         f = gzopen(file, "rb");
579         if (f == NULL) return -1;
580
581         gzread(f, header, sizeof(header));
582         gzread(f, &version, sizeof(u32));
583         gzread(f, &hle, sizeof(boolean));
584
585         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
586                 gzclose(f);
587                 return -1;
588         }
589         Config.HLE = hle;
590
591         if (Config.HLE)
592                 psxBiosInit();
593
594         psxCpu->Reset();
595         gzseek(f, 128 * 96 * 3, SEEK_CUR);
596
597         gzread(f, psxM, 0x00200000);
598         gzread(f, psxR, 0x00080000);
599         gzread(f, psxH, 0x00010000);
600         gzread(f, (void *)&psxRegs, sizeof(psxRegs));
601
602         if (Config.HLE)
603                 psxBiosFreeze(0);
604
605         // gpu
606         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
607         gzread(f, gpufP, sizeof(GPUFreeze_t));
608         GPU_freeze(0, gpufP);
609         free(gpufP);
610         if (HW_GPU_STATUS == 0)
611                 HW_GPU_STATUS = GPU_readStatus();
612
613         // spu
614         gzread(f, &Size, 4);
615         spufP = (SPUFreeze_t *)malloc(Size);
616         gzread(f, spufP, Size);
617         SPU_freeze(0, spufP);
618         free(spufP);
619
620         sioFreeze(f, 0);
621         cdrFreeze(f, 0);
622         psxHwFreeze(f, 0);
623         psxRcntFreeze(f, 0);
624         mdecFreeze(f, 0);
625
626         gzclose(f);
627         new_dyna_restore();
628
629         return 0;
630 }
631
632 int CheckState(const char *file) {
633         gzFile f;
634         char header[32];
635         u32 version;
636         boolean hle;
637
638         f = gzopen(file, "rb");
639         if (f == NULL) return -1;
640
641         gzread(f, header, sizeof(header));
642         gzread(f, &version, sizeof(u32));
643         gzread(f, &hle, sizeof(boolean));
644
645         gzclose(f);
646
647         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
648                 return -1;
649
650         return 0;
651 }
652
653 // NET Function Helpers
654
655 int SendPcsxInfo() {
656         if (NET_recvData == NULL || NET_sendData == NULL)
657                 return 0;
658
659         NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
660         NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
661         NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
662         NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
663         NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
664         NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
665
666         return 0;
667 }
668
669 int RecvPcsxInfo() {
670         int tmp;
671
672         if (NET_recvData == NULL || NET_sendData == NULL)
673                 return 0;
674
675         NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
676         NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
677         NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
678         NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
679         NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
680
681         SysUpdate();
682
683         tmp = Config.Cpu;
684         NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
685         if (tmp != Config.Cpu) {
686                 psxCpu->Shutdown();
687 #ifdef PSXREC
688                 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
689                 else psxCpu = &psxRec;
690 #else
691                 psxCpu = &psxInt;
692 #endif
693                 if (psxCpu->Init() == -1) {
694                         SysClose(); return -1;
695                 }
696                 psxCpu->Reset();
697         }
698
699         return 0;
700 }
701
702 // remove the leading and trailing spaces in a string
703 void trim(char *str) {
704         int pos = 0;
705         char *dest = str;
706
707         // skip leading blanks
708         while (str[pos] <= ' ' && str[pos] > 0)
709                 pos++;
710
711         while (str[pos]) {
712                 *(dest++) = str[pos];
713                 pos++;
714         }
715
716         *(dest--) = '\0'; // store the null
717
718         // remove trailing blanks
719         while (dest >= str && *dest <= ' ' && *dest > 0)
720                 *(dest--) = '\0';
721 }
722
723 // lookup table for crc calculation
724 static unsigned short crctab[256] = {
725         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
726         0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
727         0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
728         0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
729         0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
730         0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
731         0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
732         0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
733         0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
734         0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
735         0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
736         0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
737         0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
738         0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
739         0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
740         0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
741         0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
742         0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
743         0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
744         0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
745         0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
746         0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
747         0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
748         0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
749         0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
750         0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
751         0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
752         0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
753         0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
754 };
755
756 u16 calcCrc(u8 *d, int len) {
757         u16 crc = 0;
758         int i;
759
760         for (i = 0; i < len; i++) {
761                 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
762         }
763
764         return ~crc;
765 }