psxcounters: use higher precision for vsync timing
[pcsx_rearmed.git] / libpcsxcore / sio.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 * SIO functions.
22 */
23
24 #include "sio.h"
25 #include <sys/stat.h>
26
27 // Status Flags
28 #define TX_RDY          0x0001
29 #define RX_RDY          0x0002
30 #define TX_EMPTY        0x0004
31 #define PARITY_ERR      0x0008
32 #define RX_OVERRUN      0x0010
33 #define FRAMING_ERR     0x0020
34 #define SYNC_DETECT     0x0040
35 #define DSR                     0x0080
36 #define CTS                     0x0100
37 #define IRQ                     0x0200
38
39 // Control Flags
40 #define TX_PERM         0x0001
41 #define DTR                     0x0002
42 #define RX_PERM         0x0004
43 #define BREAK           0x0008
44 #define RESET_ERR       0x0010
45 #define RTS                     0x0020
46 #define SIO_RESET       0x0040
47
48 // *** FOR WORKS ON PADS AND MEMORY CARDS *****
49
50 static unsigned char buf[256];
51 static unsigned char cardh1[4] = { 0xff, 0x08, 0x5a, 0x5d };
52 static unsigned char cardh2[4] = { 0xff, 0x08, 0x5a, 0x5d };
53
54 // Transfer Ready and the Buffer is Empty
55 // static unsigned short StatReg = 0x002b;
56 static unsigned short StatReg = TX_RDY | TX_EMPTY;
57 static unsigned short ModeReg;
58 static unsigned short CtrlReg;
59 static unsigned short BaudReg;
60
61 static unsigned int bufcount;
62 static unsigned int parp;
63 static unsigned int mcdst, rdwr;
64 static unsigned char adrH, adrL;
65 static unsigned int padst;
66
67 char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
68 char McdDisable[2];
69
70 #define SIO_INT(eCycle) { \
71         if (!Config.Sio) { \
72                 psxRegs.interrupt |= (1 << PSXINT_SIO); \
73                 psxRegs.intCycle[PSXINT_SIO].cycle = eCycle; \
74                 psxRegs.intCycle[PSXINT_SIO].sCycle = psxRegs.cycle; \
75                 new_dyna_set_event(PSXINT_SIO, eCycle); \
76         } \
77 }
78
79 // clk cycle byte
80 // 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
81 // TODO: add SioModePrescaler and BaudReg
82 #define SIO_CYCLES              535
83
84 void sioWrite8(unsigned char value) {
85 #ifdef PAD_LOG
86         PAD_LOG("sio write8 %x\n", value);
87 #endif
88         switch (padst) {
89                 case 1: SIO_INT(SIO_CYCLES);
90                         if ((value & 0x40) == 0x40) {
91                                 padst = 2; parp = 1;
92                                 if (!Config.UseNet) {
93                                         switch (CtrlReg & 0x2002) {
94                                                 case 0x0002:
95                                                         buf[parp] = PAD1_poll(value);
96                                                         break;
97                                                 case 0x2002:
98                                                         buf[parp] = PAD2_poll(value);
99                                                         break;
100                                         }
101                                 }/* else {
102 //                                      SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]);
103                                 }*/
104
105                                 if (!(buf[parp] & 0x0f)) {
106                                         bufcount = 2 + 32;
107                                 } else {
108                                         bufcount = 2 + (buf[parp] & 0x0f) * 2;
109                                 }
110                                 if (buf[parp] == 0x41) {
111                                         switch (value) {
112                                                 case 0x43:
113                                                         buf[1] = 0x43;
114                                                         break;
115                                                 case 0x45:
116                                                         buf[1] = 0xf3;
117                                                         break;
118                                         }
119                                 }
120                         }
121                         else padst = 0;
122                         return;
123                 case 2:
124                         parp++;
125 /*                      if (buf[1] == 0x45) {
126                                 buf[parp] = 0;
127                                 SIO_INT(SIO_CYCLES);
128                                 return;
129                         }*/
130                         if (!Config.UseNet) {
131                                 switch (CtrlReg & 0x2002) {
132                                         case 0x0002: buf[parp] = PAD1_poll(value); break;
133                                         case 0x2002: buf[parp] = PAD2_poll(value); break;
134                                 }
135                         }
136
137                         if (parp == bufcount) { padst = 0; return; }
138                         SIO_INT(SIO_CYCLES);
139                         return;
140         }
141
142         switch (mcdst) {
143                 case 1:
144                         SIO_INT(SIO_CYCLES);
145                         if (rdwr) { parp++; return; }
146                         parp = 1;
147                         switch (value) {
148                                 case 0x52: rdwr = 1; break;
149                                 case 0x57: rdwr = 2; break;
150                                 default: mcdst = 0;
151                         }
152                         return;
153                 case 2: // address H
154                         SIO_INT(SIO_CYCLES);
155                         adrH = value;
156                         *buf = 0;
157                         parp = 0;
158                         bufcount = 1;
159                         mcdst = 3;
160                         return;
161                 case 3: // address L
162                         SIO_INT(SIO_CYCLES);
163                         adrL = value;
164                         *buf = adrH;
165                         parp = 0;
166                         bufcount = 1;
167                         mcdst = 4;
168                         return;
169                 case 4:
170                         SIO_INT(SIO_CYCLES);
171                         parp = 0;
172                         switch (rdwr) {
173                                 case 1: // read
174                                         buf[0] = 0x5c;
175                                         buf[1] = 0x5d;
176                                         buf[2] = adrH;
177                                         buf[3] = adrL;
178                                         switch (CtrlReg & 0x2002) {
179                                                 case 0x0002:
180                                                         memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
181                                                         break;
182                                                 case 0x2002:
183                                                         memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
184                                                         break;
185                                         }
186                                         {
187                                         char xor = 0;
188                                         int i;
189                                         for (i = 2; i < 128 + 4; i++)
190                                                 xor ^= buf[i];
191                                         buf[132] = xor;
192                                         }
193                                         buf[133] = 0x47;
194                                         bufcount = 133;
195                                         break;
196                                 case 2: // write
197                                         buf[0] = adrL;
198                                         buf[1] = value;
199                                         buf[129] = 0x5c;
200                                         buf[130] = 0x5d;
201                                         buf[131] = 0x47;
202                                         bufcount = 131;
203                                         break;
204                         }
205                         mcdst = 5;
206                         return;
207                 case 5:
208                         parp++;
209                         if ((rdwr == 1 && parp == 132) ||
210                             (rdwr == 2 && parp == 129)) {
211                                 // clear "new card" flags
212                                 if (CtrlReg & 0x2000)
213                                         cardh2[1] &= ~8;
214                                 else
215                                         cardh1[1] &= ~8;
216                         }
217                         if (rdwr == 2) {
218                                 if (parp < 128) buf[parp + 1] = value;
219                         }
220                         SIO_INT(SIO_CYCLES);
221                         return;
222         }
223
224         switch (value) {
225                 case 0x01: // start pad
226                         StatReg |= RX_RDY;              // Transfer is Ready
227
228                         if (!Config.UseNet) {
229                                 switch (CtrlReg & 0x2002) {
230                                         case 0x0002: buf[0] = PAD1_startPoll(1); break;
231                                         case 0x2002: buf[0] = PAD2_startPoll(2); break;
232                                 }
233                         } else {
234                                 if ((CtrlReg & 0x2002) == 0x0002) {
235                                         int i, j;
236
237                                         PAD1_startPoll(1);
238                                         buf[0] = 0;
239                                         buf[1] = PAD1_poll(0x42);
240                                         if (!(buf[1] & 0x0f)) {
241                                                 bufcount = 32;
242                                         } else {
243                                                 bufcount = (buf[1] & 0x0f) * 2;
244                                         }
245                                         buf[2] = PAD1_poll(0);
246                                         i = 3;
247                                         j = bufcount;
248                                         while (j--) {
249                                                 buf[i++] = PAD1_poll(0);
250                                         }
251                                         bufcount+= 3;
252
253                                         if (NET_sendPadData(buf, bufcount) == -1)
254                                                 netError();
255
256                                         if (NET_recvPadData(buf, 1) == -1)
257                                                 netError();
258                                         if (NET_recvPadData(buf + 128, 2) == -1)
259                                                 netError();
260                                 } else {
261                                         memcpy(buf, buf + 128, 32);
262                                 }
263                         }
264
265                         bufcount = 2;
266                         parp = 0;
267                         padst = 1;
268                         SIO_INT(SIO_CYCLES);
269                         return;
270                 case 0x81: // start memcard
271                         if (CtrlReg & 0x2000)
272                         {
273                                 if (McdDisable[1])
274                                         goto no_device;
275                                 memcpy(buf, cardh2, 4);
276                         }
277                         else
278                         {
279                                 if (McdDisable[0])
280                                         goto no_device;
281                                 memcpy(buf, cardh1, 4);
282                         }
283                         StatReg |= RX_RDY;
284                         parp = 0;
285                         bufcount = 3;
286                         mcdst = 1;
287                         rdwr = 0;
288                         SIO_INT(SIO_CYCLES);
289                         return;
290                 default:
291                 no_device:
292                         StatReg |= RX_RDY;
293                         buf[0] = 0xff;
294                         parp = 0;
295                         bufcount = 0;
296                         return;
297         }
298 }
299
300 void sioWriteStat16(unsigned short value) {
301 }
302
303 void sioWriteMode16(unsigned short value) {
304         ModeReg = value;
305 }
306
307 void sioWriteCtrl16(unsigned short value) {
308         CtrlReg = value & ~RESET_ERR;
309         if (value & RESET_ERR) StatReg &= ~IRQ;
310         if ((CtrlReg & SIO_RESET) || !(CtrlReg & DTR)) {
311                 padst = 0; mcdst = 0; parp = 0;
312                 StatReg = TX_RDY | TX_EMPTY;
313                 psxRegs.interrupt &= ~(1 << PSXINT_SIO);
314         }
315 }
316
317 void sioWriteBaud16(unsigned short value) {
318         BaudReg = value;
319 }
320
321 unsigned char sioRead8() {
322         unsigned char ret = 0;
323
324         if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
325 //              StatReg &= ~RX_OVERRUN;
326                 ret = buf[parp];
327                 if (parp == bufcount) {
328                         StatReg &= ~RX_RDY;             // Receive is not Ready now
329                         if (mcdst == 5) {
330                                 mcdst = 0;
331                                 if (rdwr == 2) {
332                                         switch (CtrlReg & 0x2002) {
333                                                 case 0x0002:
334                                                         memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
335                                                         SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
336                                                         break;
337                                                 case 0x2002:
338                                                         memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
339                                                         SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
340                                                         break;
341                                         }
342                                 }
343                         }
344                         if (padst == 2) padst = 0;
345                         if (mcdst == 1) {
346                                 mcdst = 2;
347                                 StatReg|= RX_RDY;
348                         }
349                 }
350         }
351
352 #ifdef PAD_LOG
353         PAD_LOG("sio read8 ;ret = %x\n", ret);
354 #endif
355         return ret;
356 }
357
358 unsigned short sioReadStat16() {
359         return StatReg;
360 }
361
362 unsigned short sioReadMode16() {
363         return ModeReg;
364 }
365
366 unsigned short sioReadCtrl16() {
367         return CtrlReg;
368 }
369
370 unsigned short sioReadBaud16() {
371         return BaudReg;
372 }
373
374 void netError() {
375         ClosePlugins();
376         SysMessage(_("Connection closed!\n"));
377
378         CdromId[0] = '\0';
379         CdromLabel[0] = '\0';
380
381         SysRunGui();
382 }
383
384 void sioInterrupt() {
385 #ifdef PAD_LOG
386         PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
387 #endif
388 //      SysPrintf("Sio Interrupt\n");
389         if (!(StatReg & IRQ)) {
390                 StatReg |= IRQ;
391                 psxHu32ref(0x1070) |= SWAPu32(0x80);
392         }
393 }
394
395 void LoadMcd(int mcd, char *str) {
396         FILE *f;
397         char *data = NULL;
398
399         if (mcd != 1 && mcd != 2)
400                 return;
401
402         if (mcd == 1) {
403                 data = Mcd1Data;
404                 cardh1[1] |= 8; // mark as new
405         }
406         if (mcd == 2) {
407                 data = Mcd2Data;
408                 cardh2[1] |= 8;
409         }
410
411         McdDisable[mcd - 1] = 0;
412         if (str == NULL || *str == 0) {
413                 McdDisable[mcd - 1] = 1;
414                 return;
415         }
416         f = fopen(str, "rb");
417         if (f == NULL) {
418                 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
419                 CreateMcd(str);
420                 f = fopen(str, "rb");
421                 if (f != NULL) {
422                         struct stat buf;
423
424                         if (stat(str, &buf) != -1) {
425                                 if (buf.st_size == MCD_SIZE + 64)
426                                         fseek(f, 64, SEEK_SET);
427                                 else if(buf.st_size == MCD_SIZE + 3904)
428                                         fseek(f, 3904, SEEK_SET);
429                         }
430                         fread(data, 1, MCD_SIZE, f);
431                         fclose(f);
432                 }
433                 else
434                         SysMessage(_("Memory card %s failed to load!\n"), str);
435         }
436         else {
437                 struct stat buf;
438                 SysPrintf(_("Loading memory card %s\n"), str);
439                 if (stat(str, &buf) != -1) {
440                         if (buf.st_size == MCD_SIZE + 64)
441                                 fseek(f, 64, SEEK_SET);
442                         else if(buf.st_size == MCD_SIZE + 3904)
443                                 fseek(f, 3904, SEEK_SET);
444                 }
445                 fread(data, 1, MCD_SIZE, f);
446                 fclose(f);
447         }
448 }
449
450 void LoadMcds(char *mcd1, char *mcd2) {
451         LoadMcd(1, mcd1);
452         LoadMcd(2, mcd2);
453 }
454
455 void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
456         FILE *f;
457
458         f = fopen(mcd, "r+b");
459         if (f != NULL) {
460                 struct stat buf;
461
462                 if (stat(mcd, &buf) != -1) {
463                         if (buf.st_size == MCD_SIZE + 64)
464                                 fseek(f, adr + 64, SEEK_SET);
465                         else if (buf.st_size == MCD_SIZE + 3904)
466                                 fseek(f, adr + 3904, SEEK_SET);
467                         else
468                                 fseek(f, adr, SEEK_SET);
469                 } else
470                         fseek(f, adr, SEEK_SET);
471
472                 fwrite(data + adr, 1, size, f);
473                 fclose(f);
474                 return;
475         }
476
477 #if 0
478         // try to create it again if we can't open it
479         f = fopen(mcd, "wb");
480         if (f != NULL) {
481                 fwrite(data, 1, MCD_SIZE, f);
482                 fclose(f);
483         }
484 #endif
485
486         ConvertMcd(mcd, data);
487 }
488
489 void CreateMcd(char *mcd) {
490         FILE *f;
491         struct stat buf;
492         int s = MCD_SIZE;
493         int i = 0, j;
494
495         f = fopen(mcd, "wb");
496         if (f == NULL)
497                 return;
498
499         if (stat(mcd, &buf) != -1) {
500                 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
501                         s = s + 3904;
502                         fputc('1', f);
503                         s--;
504                         fputc('2', f);
505                         s--;
506                         fputc('3', f);
507                         s--;
508                         fputc('-', f);
509                         s--;
510                         fputc('4', f);
511                         s--;
512                         fputc('5', f);
513                         s--;
514                         fputc('6', f);
515                         s--;
516                         fputc('-', f);
517                         s--;
518                         fputc('S', f);
519                         s--;
520                         fputc('T', f);
521                         s--;
522                         fputc('D', f);
523                         s--;
524                         for (i = 0; i < 7; i++) {
525                                 fputc(0, f);
526                                 s--;
527                         }
528                         fputc(1, f);
529                         s--;
530                         fputc(0, f);
531                         s--;
532                         fputc(1, f);
533                         s--;
534                         fputc('M', f);
535                         s--;
536                         fputc('Q', f);
537                         s--;
538                         for (i = 0; i < 14; i++) {
539                                 fputc(0xa0, f);
540                                 s--;
541                         }
542                         fputc(0, f);
543                         s--;
544                         fputc(0xff, f);
545                         while (s-- > (MCD_SIZE + 1))
546                                 fputc(0, f);
547                 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
548                         s = s + 64;
549                         fputc('V', f);
550                         s--;
551                         fputc('g', f);
552                         s--;
553                         fputc('s', f);
554                         s--;
555                         fputc('M', f);
556                         s--;
557                         for (i = 0; i < 3; i++) {
558                                 fputc(1, f);
559                                 s--;
560                                 fputc(0, f);
561                                 s--;
562                                 fputc(0, f);
563                                 s--;
564                                 fputc(0, f);
565                                 s--;
566                         }
567                         fputc(0, f);
568                         s--;
569                         fputc(2, f);
570                         while (s-- > (MCD_SIZE + 1))
571                                 fputc(0, f);
572                 }
573         }
574         fputc('M', f);
575         s--;
576         fputc('C', f);
577         s--;
578         while (s-- > (MCD_SIZE - 127))
579                 fputc(0, f);
580         fputc(0xe, f);
581         s--;
582
583         for (i = 0; i < 15; i++) { // 15 blocks
584                 fputc(0xa0, f);
585                 s--;
586                 fputc(0x00, f);
587                 s--;
588                 fputc(0x00, f);
589                 s--;
590                 fputc(0x00, f);
591                 s--;
592                 fputc(0x00, f);
593                 s--;
594                 fputc(0x00, f);
595                 s--;
596                 fputc(0x00, f);
597                 s--;
598                 fputc(0x00, f);
599                 s--;
600                 fputc(0xff, f);
601                 s--;
602                 fputc(0xff, f);
603                 s--;
604                 for (j = 0; j < 117; j++) {
605                         fputc(0x00, f);
606                         s--;
607                 }
608                 fputc(0xa0, f);
609                 s--;
610         }
611
612         for (i = 0; i < 20; i++) {
613                 fputc(0xff, f);
614                 s--;
615                 fputc(0xff, f);
616                 s--;
617                 fputc(0xff, f);
618                 s--;
619                 fputc(0xff, f);
620                 s--;
621                 fputc(0x00, f);
622                 s--;
623                 fputc(0x00, f);
624                 s--;
625                 fputc(0x00, f);
626                 s--;
627                 fputc(0x00, f);
628                 s--;
629                 fputc(0xff, f);
630                 s--;
631                 fputc(0xff, f);
632                 s--;
633                 for (j = 0; j < 118; j++) {
634                         fputc(0x00, f);
635                         s--;
636                 }
637         }
638
639         while ((s--) >= 0)
640                 fputc(0, f);
641
642         fclose(f);
643 }
644
645 void ConvertMcd(char *mcd, char *data) {
646         FILE *f;
647         int i = 0;
648         int s = MCD_SIZE;
649
650         if (strstr(mcd, ".gme")) {
651                 f = fopen(mcd, "wb");
652                 if (f != NULL) {
653                         fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
654                         fclose(f);
655                 }
656                 f = fopen(mcd, "r+");
657                 s = s + 3904;
658                 fputc('1', f); s--;
659                 fputc('2', f); s--;
660                 fputc('3', f); s--;
661                 fputc('-', f); s--;
662                 fputc('4', f); s--;
663                 fputc('5', f); s--;
664                 fputc('6', f); s--;
665                 fputc('-', f); s--;
666                 fputc('S', f); s--;
667                 fputc('T', f); s--;
668                 fputc('D', f); s--;
669                 for (i = 0; i < 7; i++) {
670                         fputc(0, f); s--;
671                 }
672                 fputc(1, f); s--;
673                 fputc(0, f); s--;
674                 fputc(1, f); s--;
675                 fputc('M', f); s--;
676                 fputc('Q', f); s--;
677                 for(i=0;i<14;i++) {
678                         fputc(0xa0, f); s--;
679                 }
680                 fputc(0, f); s--;
681                 fputc(0xff, f);
682                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
683                 fclose(f);
684         } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
685                 f = fopen(mcd, "wb");
686                 if (f != NULL) {
687                         fwrite(data-64, 1, MCD_SIZE+64, f);
688                         fclose(f);
689                 }
690                 f = fopen(mcd, "r+");
691                 s = s + 64;
692                 fputc('V', f); s--;
693                 fputc('g', f); s--;
694                 fputc('s', f); s--;
695                 fputc('M', f); s--;
696                 for(i=0;i<3;i++) {
697                         fputc(1, f); s--;
698                         fputc(0, f); s--;
699                         fputc(0, f); s--;
700                         fputc(0, f); s--;
701                 }
702                 fputc(0, f); s--;
703                 fputc(2, f);
704                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
705                 fclose(f);
706         } else {
707                 f = fopen(mcd, "wb");
708                 if (f != NULL) {
709                         fwrite(data, 1, MCD_SIZE, f);
710                         fclose(f);
711                 }
712         }
713 }
714
715 void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
716         char *data = NULL, *ptr, *str, *sstr;
717         unsigned short clut[16];
718         unsigned short c;
719         int i, x;
720
721         memset(Info, 0, sizeof(McdBlock));
722
723         if (mcd != 1 && mcd != 2)
724                 return;
725
726         if (McdDisable[mcd - 1])
727                 return;
728
729         if (mcd == 1) data = Mcd1Data;
730         if (mcd == 2) data = Mcd2Data;
731
732         ptr = data + block * 8192 + 2;
733
734         Info->IconCount = *ptr & 0x3;
735
736         ptr += 2;
737
738         x = 0;
739
740         str = Info->Title;
741         sstr = Info->sTitle;
742
743         for (i = 0; i < 48; i++) {
744                 c = *(ptr) << 8;
745                 c |= *(ptr + 1);
746                 if (!c) break;
747
748                 // Convert ASCII characters to half-width
749                 if (c >= 0x8281 && c <= 0x829A)
750                         c = (c - 0x8281) + 'a';
751                 else if (c >= 0x824F && c <= 0x827A)
752                         c = (c - 0x824F) + '0';
753                 else if (c == 0x8140) c = ' ';
754                 else if (c == 0x8143) c = ',';
755                 else if (c == 0x8144) c = '.';
756                 else if (c == 0x8146) c = ':';
757                 else if (c == 0x8147) c = ';';
758                 else if (c == 0x8148) c = '?';
759                 else if (c == 0x8149) c = '!';
760                 else if (c == 0x815E) c = '/';
761                 else if (c == 0x8168) c = '"';
762                 else if (c == 0x8169) c = '(';
763                 else if (c == 0x816A) c = ')';
764                 else if (c == 0x816D) c = '[';
765                 else if (c == 0x816E) c = ']';
766                 else if (c == 0x817C) c = '-';
767                 else {
768                         str[i] = ' ';
769                         sstr[x++] = *ptr++; sstr[x++] = *ptr++;
770                         continue;
771                 }
772
773                 str[i] = sstr[x++] = c;
774                 ptr += 2;
775         }
776
777         trim(str);
778         trim(sstr);
779
780         ptr = data + block * 8192 + 0x60; // icon palette data
781
782         for (i = 0; i < 16; i++) {
783                 clut[i] = *((unsigned short *)ptr);
784                 ptr += 2;
785         }
786
787         for (i = 0; i < Info->IconCount; i++) {
788                 short *icon = &Info->Icon[i * 16 * 16];
789
790                 ptr = data + block * 8192 + 128 + 128 * i; // icon data
791
792                 for (x = 0; x < 16 * 16; x++) {
793                         icon[x++] = clut[*ptr & 0xf];
794                         icon[x] = clut[*ptr >> 4];
795                         ptr++;
796                 }
797         }
798
799         ptr = data + block * 128;
800
801         Info->Flags = *ptr;
802
803         ptr += 0xa;
804         strncpy(Info->ID, ptr, 12);
805         ptr += 12;
806         strncpy(Info->Name, ptr, 16);
807 }
808
809 int sioFreeze(gzFile f, int Mode) {
810         gzfreeze(buf, sizeof(buf));
811         gzfreeze(&StatReg, sizeof(StatReg));
812         gzfreeze(&ModeReg, sizeof(ModeReg));
813         gzfreeze(&CtrlReg, sizeof(CtrlReg));
814         gzfreeze(&BaudReg, sizeof(BaudReg));
815         gzfreeze(&bufcount, sizeof(bufcount));
816         gzfreeze(&parp, sizeof(parp));
817         gzfreeze(&mcdst, sizeof(mcdst));
818         gzfreeze(&rdwr, sizeof(rdwr));
819         gzfreeze(&adrH, sizeof(adrH));
820         gzfreeze(&adrL, sizeof(adrL));
821         gzfreeze(&padst, sizeof(padst));
822
823         return 0;
824 }